home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 October: Mac OS SDK / Dev.CD Oct 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw GX / Programming Stuff / Sample Code / Printing Samples / Printer Drivers… / ImageWriterLQ (alt. rdip) / UniversalMessageIntf.c < prev    next >
Encoding:
Text File  |  1996-06-15  |  86.7 KB  |  2,812 lines  |  [TEXT/MPS ]

  1. /*---------------------------------------------------------------------------
  2. FILENAME
  3.     UniversalMessageIntf.c
  4.  
  5. DESCRIPTION
  6.     This file contains the routines which override the universal imaging 
  7.     messages that the ImageWriter LQ utilizes.
  8.         
  9. COPYRIGHT
  10.     Copyright Apple Computer, Inc. 1992-1994
  11.     All rights reserved. 
  12.     
  13. INTERFACE ROUTINES:
  14.     SD_Initialize
  15.     SD_ShutDown
  16.     SD_JobFormatDialog
  17.     SD_JobFormatModeQuery
  18.     SD_OpenConnection
  19.     SD_StartSendPage
  20.     SD_RenderPage
  21.     SD_DefaultPrinter
  22.     SD_SetupImageData
  23.     SD_FetchTaggedData
  24.     SD_RasterPackageBitmap
  25.     SD_RasterLineFeed
  26.  
  27.     12/20/93        dmh    Sync'd with the shipping 1.0b3 GX driver.
  28.      8/28/94        dmh    Sync'd with the shipping 1.0.1 GX driver.
  29.      8/28/94        dmh    Universalized.
  30.      6/14/96        cn        Updated to support Universal Interfaces 2.1.
  31.  
  32. -------------------------------------------------------------------------------- */
  33.  
  34. // Include the standard Mac header files 
  35. #include "MacIncludes.h"
  36.  
  37. // Include the new QuickDraw GX graphics header files 
  38. #include <GXGraphics.h>
  39. #include <GraphicsLibraries.h>
  40. #include <GXMath.h>
  41. #include <QDLibrary.h>
  42. #include <FontLibrary.h>
  43. #include <GXLayout.h>
  44.  
  45. // Include the required Printing Manager header files 
  46. #include <GXPrinting.h>
  47. #include <GXPrinterDrivers.h>
  48. #include <Collections.h>
  49. #include <GXMessages.h>
  50. #include <PrintingLibraries.h>
  51.  
  52. #include <GXExceptions.h>
  53.  
  54. // Include the internal driver constants and types used by this module 
  55. #include "LQResources.h"
  56. #include "UniversalMessageIntf.h"
  57. #include "OldAPIMessageIntf.h"
  58. #include "DialogRoutines.h"
  59.  
  60. /***************************************************************************************
  61. *                                                 CONSTANTS                                                         *
  62. ***************************************************************************************/                        
  63.  
  64. // ImageWriter LQ device commands
  65.  
  66. #define    kEscape                            (char) 27        // <Escape> character
  67. #define    kLineFeed                        (char) 10        // Line feed character
  68. #define    kDevStatusCommand                "\033?"            // <Escape>? - used to query the status of the printer
  69.  
  70. #define    kLowResGraphicsCommand        (char) 'G'        //    72 dpi graphics mode
  71. #define    kHighResGraphicsCommand        (char) 'C'        //    216 dpi graphics mode
  72.  
  73. #define    kLowResMarginsCommand        (char) 'F'        //    72 dpi margins command
  74. #define    kHighResMarginsCommand        (char) 'h'        //    216 dpi margins command
  75.  
  76. #define    kSetColorCommand                (char) 'K'        //    Command to select color
  77.  
  78.  
  79. // Constants used with the ScanLineRecord structure
  80.  
  81. #define    kScanLineHdrSize                15                    //    Size of the constant portion of the scan line structure
  82.  
  83.  
  84. /***************************************************************************************
  85. *                                                 TYPES                                                                 *
  86. ***************************************************************************************/                        
  87.  
  88. // ScanLineRecord -    Structure overlayed within a buffer to fill in the comands and data needed to
  89. //                            package one complete scan line.
  90. typedef struct
  91. {
  92.     char        cMarginsEscape;            // kEscape character
  93.     char        cMarginsCommand;            // Set Margins command character
  94.     char        cIndentDistance[4];        // Number of pixels to indent
  95.  
  96.     char        cColorEscape;                // kEscape character
  97.     char        cSetColorCommand;            // Set color command
  98.     char        cColor;                        // The color to use
  99.  
  100.     char        cEscape;                        // kEscape character
  101.     char        cCommand;                    // Enter graphics mode command
  102.     char        cLineStrLength[4];            // number of dots to print
  103.     char        iTheData[9072];            // Bits for the data, enough for one line's worth
  104. }    ScanLineRecord,
  105.     *ScanLinePtr;
  106.  
  107.  
  108. /***************************************************************************************
  109. *                                         INTERNAL ROUTINES                                                     *
  110. ***************************************************************************************/                        
  111.  
  112. /****************************************************************************************
  113.  
  114.                             Long2Dec
  115.                             
  116.     function:
  117.                 This routine converts a long integer into an ASCII string representing the
  118.                 numeric value.  If the number is less than four digits, then it's padded
  119.                 with leading zeros.
  120.                 
  121.     parameters:                
  122.                 theNumber            number to convert to a string
  123.                 emitStringHere        location in which to store the ASCII string
  124.                 
  125.     returns:
  126.                 none
  127.     
  128. ****************************************************************************************/
  129. void Long2Dec(long theNumber, Ptr emitStringHere)
  130. {    
  131.     char        aString[10];
  132.     short        i;
  133.     short        actualWidth;
  134.     short        theLength;
  135.     
  136.     NumToString(theNumber, (unsigned char *) aString);
  137.     
  138.     // Get the width of the string, check for being too small
  139.  
  140.     theLength = StrLength(aString);
  141.     actualWidth = theLength;
  142.     if (actualWidth < 4)
  143.         actualWidth = 4;
  144.         
  145.     // output the string, padding with leading zeros
  146.     
  147.     theLength = actualWidth - theLength;
  148.     for (i = 0; i < actualWidth; ++i)
  149.     {
  150.         *emitStringHere++ = (i < theLength) ? '0' : aString[(i + 1) - theLength];
  151.     }
  152. }
  153. /* Long2Dec */
  154.  
  155.  
  156. /****************************************************************************************
  157.  
  158.                             PrinterHasColorRibbon
  159.                             
  160.     function:
  161.                 This routine is a utility function that returns true if the desktop printer
  162.                 configuration file specifies that the printer contains a color ribbon, and
  163.                 false if it has a black and white ribbon.
  164.                 
  165.     parameters:                
  166.                 None
  167.                 
  168.     returns:
  169.                 Boolean        true => printer has color ribbon; false => black and white ribbon
  170.     
  171. ****************************************************************************************/
  172. Boolean PrinterHasColorRibbon(void)
  173. {
  174.     OSErr                        anErr;
  175.     Boolean                    hasColor = true;
  176.     Str32                        deviceName;
  177.     IWLQConfigInfoHdl        configData;
  178.     
  179.     // if not formatting to a particular device, assume color ribbon, for widest range of colorSpaces
  180.  
  181.     GXGetPrinterName(GXGetJobOutputPrinter(GXGetJob()), deviceName);
  182.     if ( StrLength(deviceName) > 0 )
  183.     {
  184.         // if we are going to a particular device, assume no color, as that is more common
  185.         hasColor = false;
  186.         
  187.         anErr = GXFetchDTPData(deviceName, kIWLQConfigType, kIWLQConfigID, (Handle *) &configData);
  188.         if (anErr == noErr)
  189.         {
  190.             hasColor = (*configData)->hasColorRibbon;
  191.             DisposHandle((Handle) configData);
  192.         }
  193.     }
  194.     
  195.     return(hasColor);
  196. }
  197. /* PrinterHasColorRibbon */
  198.  
  199.  
  200. /****************************************************************************************
  201.  
  202.                             PrinterHasTrays
  203.                             
  204.     function:
  205.                 This routine is a utility function that returns the number of sheet feeder trays
  206.                 that are attached to the desktop printer.  If no sheet feeder is attached, then 
  207.                 the function returns zero.
  208.                 
  209.     parameters:                
  210.                 None
  211.                 
  212.     returns:
  213.                 char        number of sheet feeder trays attached to the printer; zero if no sheet feeder
  214.     
  215. ****************************************************************************************/
  216. char PrinterHasTrays(void)
  217. {
  218.     OSErr                        anErr;
  219.     char                        numTrays = 0;    //    Assume no trays available (common case)
  220.     Str32                        deviceName;
  221.     IWLQConfigInfoHdl        configData;
  222.     
  223.     // if not formatting to a particular device, assume color ribbon, for widest range of colorSpaces
  224.  
  225.     GXGetPrinterName(GXGetJobOutputPrinter(GXGetJob()), deviceName);
  226.     if ( StrLength(deviceName) > 0 )
  227.     {
  228.         anErr = GXFetchDTPData(deviceName, kIWLQConfigType, kIWLQConfigID, (Handle *) &configData);
  229.         if (anErr == noErr)
  230.         {
  231.             numTrays = (*configData)->numTrays;
  232.             DisposHandle((Handle) configData);
  233.         }
  234.     }
  235.     
  236.     return(numTrays);
  237. }
  238. /* PrinterHasTrays */
  239.  
  240.  
  241. /****************************************************************************************
  242.  
  243.                             UpdateDTPConfigInfo
  244.                             
  245.     function:
  246.                 This routine is a utility function that queries the printer to determine its
  247.                 configuration (color ribbon, trays, etc.) and updates the config info. in the
  248.                 desktop printer file to reflect this new configuration.
  249.                 
  250.     parameters:                
  251.                 None
  252.                 
  253.     returns:
  254.                 OSErr        error code
  255.     
  256. ****************************************************************************************/
  257. OSErr UpdateDTPConfigInfo(void)
  258. {
  259.     OSErr                        anErr;
  260.     IWLQConfigInfoHdl        configData;
  261.     char                        statusString[9];
  262.     long                        statusStrLength;
  263.     Boolean                    wasSheetfeederAttached;
  264.     gxJob                        theJob = GXGetJob();
  265.         
  266.     // Determine if there was a sheetfeeder attached to the printer the last time we updated the config file
  267.     wasSheetfeederAttached = PrinterHasTrays() > 0;
  268.     
  269.     // Make a handle in which to store the config. info.
  270.     
  271.     configData = (IWLQConfigInfoHdl) NewHandleClear( sizeof(IWLQConfigInfo) );
  272.     anErr = MemError();
  273.     require(anErr == noErr, NewHandleClear);
  274.     
  275.     // Now query the printer
  276.     
  277.     statusStrLength = 9;
  278.     
  279.     anErr = Send_GXGetDeviceStatus(kDevStatusCommand, 2, statusString, &statusStrLength, "\p\n");
  280.     require(anErr == noErr, Send_GXGetDeviceStatus);
  281.     
  282.     // Scan the status string returned looking for the needed info.
  283.     
  284.     if ( (statusString[0] == 'L') && (statusString[1] == 'Q') )
  285.     {
  286.         Str32        deviceName;
  287.  
  288.         if ( statusString[3] == 'C' )    //    T => Has color ribbon
  289.         {
  290.             (*configData)->hasColorRibbon = true;
  291.         }
  292.         
  293.         if (  (statusString[3] == 'E') || 
  294.                 (statusString[3] == 'F')
  295.             )                                            //    T => Sheet feeder is installed
  296.         {
  297.             (*configData)->numTrays = statusString[4] - 0x30;
  298.         }
  299.         else
  300.         if (    (statusString[4] == 'E') ||
  301.                 (statusString[4] == 'F')
  302.             )                                            //    T => Sheet feeder is installed
  303.         {
  304.             (*configData)->numTrays = statusString[5] - 0x30;
  305.         }
  306.  
  307.         //    Update the config. file with the latest info. (our driver info.)
  308.         
  309.         GXGetPrinterName(GXGetJobOutputPrinter(theJob), deviceName);
  310.         anErr = GXWriteDTPData(deviceName, kIWLQConfigType, kIWLQConfigID, (Handle) configData);
  311.         require(anErr == noErr, WriteDTPData);
  312.  
  313.         // If this is the first time we've detected a sheet feeder, then we must set the tray info. (in the config. file)
  314.         // for the sheet feeder trays.  If this isn't the first time we've detected a sheetfeeder, we'll just use
  315.         // the last sheetfeeder tray settings.
  316.         
  317.         if ( (!wasSheetfeederAttached) && ((*configData)->numTrays > 0) )    //    T => No sheetfeeder before; clear the tray info.
  318.         {
  319.             GXSetTrayPaperType(1, NULL);    /* Reset the paper types from the default tray */
  320.         }
  321.         else if ( wasSheetfeederAttached && ((*configData)->numTrays == 0) )    //    T => Sheetfeeder before; clear the tray info.
  322.         {
  323.             GXSetTrayPaperType(1, NULL);    /* Reset the paper types from the first tray, ignore the others */
  324.         }
  325.     }
  326.     // else - not an LQ printer so don't change the config file info.
  327.  
  328.     // Dump the confog. data handle
  329.     DisposHandle((Handle) configData);
  330.  
  331.     return(anErr);
  332.     
  333.     
  334. /******* Clean-up *******/
  335.  
  336. WriteDTPData:
  337. Send_GXGetDeviceStatus:
  338.     DisposHandle((Handle) configData);
  339.     
  340. NewHandleClear:
  341.     return(anErr);
  342. }
  343. /* UpdateDTPConfigInfo */
  344.  
  345.  
  346. /****************************************************************************************
  347.  
  348.                             FixRoundRectangle
  349.                             
  350.     function:
  351.                 This routine is a utility function which rounds the coordinate values within 
  352.                 the rectangle passed in.
  353.                 
  354.     parameters:                
  355.                 r            rectangle whose coordinates are to be rounded
  356.                 
  357.     returns:
  358.                 None
  359.     
  360. ****************************************************************************************/
  361. void FixRoundRectangle(gxRectangle *r)
  362. {
  363.     r->top         = ff(FixRound(r->top));
  364.     r->left         = ff(FixRound(r->left));
  365.     r->bottom     = ff(FixRound(r->bottom));
  366.     r->right     = ff(FixRound(r->right));
  367. }
  368. /* FixRoundRectangle */
  369.  
  370.  
  371. /****************************************************************************************
  372.  
  373.                             JobIsBestQuality
  374.                             
  375.     function:
  376.                 This routine is called to determine if the job the driver is currently
  377.                 processing is to be output in best quality or rough quality. The function
  378.                 returns true if best quality, and false otherwise.
  379.                 
  380.     parameters:    
  381.                 None
  382.                 
  383.     returns:
  384.                 Boolean        true if best quality job; false otherwise
  385.     
  386. ****************************************************************************************/
  387. Boolean JobIsBestQuality(void)
  388. {
  389.     OSErr                    anErr;
  390.     Boolean                isFinal;
  391.     gxQualityInfo        jobQualitySettings;
  392.     long                    itemSize = sizeof(jobQualitySettings);
  393.  
  394.     // Retrieve the quality setting info from the job
  395.     anErr = GetCollectionItem(GXGetJobCollection(GXGetJob()), gxQualityTag, gxPrintingTagID, &itemSize, &jobQualitySettings);
  396.     check(anErr == noErr);
  397.     
  398.     isFinal = (anErr == noErr) && (jobQualitySettings.currentQuality == 1);
  399.  
  400.     return(isFinal);
  401. }
  402. /* JobIsBestQuality */
  403.  
  404.  
  405. /****************************************************************************************
  406.  
  407.                             MakeNewPrinterViewDevice
  408.                             
  409.     function:
  410.                 This routine is called to add a new view device to the printer object.  The
  411.                 viewDevice that's added will have a resolution of 216 dpi, and will have the
  412.                 set of colors specified by the theColors parameter.  The newly created 
  413.                 view device is added to the printer object.
  414.                 
  415.     parameters:                
  416.                 thePrinter        the newly allocated printer object
  417.                 theColors        the colors over which the view device is defined
  418.                 numColrs            the number of colors in the set
  419.                 
  420.     returns:
  421.                 OSErr
  422.                 
  423. ****************************************************************************************/
  424. OSErr MakeNewPrinterViewDevice(    gxPrinter        thePrinter,
  425.                                             gxSetColor        theColors[],
  426.                                             short                numColors)
  427. {
  428.     OSErr             anErr = noErr;
  429.     gxViewDevice     vd;
  430.     gxMapping        vdMapping;
  431.     gxShape            theBitmap;
  432.     gxColorSet        theColorSet;
  433.     
  434.     // Create the new viewDevice using a fake bitmap 
  435.     {
  436.         gxBitmap    aBitmap;
  437.         
  438.         aBitmap.pixelSize    = 1;
  439.         aBitmap.rowBytes    = 0;
  440.         aBitmap.width        = 0;
  441.         aBitmap.height        = 0;
  442.         aBitmap.image        = (char*)gxMissingImagePointer;
  443.         aBitmap.space        = gxNoSpace;
  444.         aBitmap.set            = nil;
  445.         aBitmap.profile    = nil;
  446.         
  447.         theBitmap = GXNewBitmap(&aBitmap, nil);
  448.         require_action( GXGetGraphicsError(nil) == noErr, NewBitmap, anErr = GXGetGraphicsError(nil); );
  449.         
  450.         vd = GXNewViewDevice(gxScreenViewDevices, theBitmap);
  451.         require_action( GXGetGraphicsError(nil) == noErr, NewViewDevice, anErr = GXGetGraphicsError(nil); );
  452.  
  453.         // Dispose of the reference to the temporary shape
  454.         GXDisposeShape(theBitmap);
  455.     }
  456.     
  457.     // Now set the view device's color space based on the set of colors passed in 
  458.     {
  459.         theColorSet = GXNewColorSet(gxRGBSpace, numColors, theColors);
  460.         require_action( GXGetGraphicsError(nil) == noErr, NewColorSet, anErr = GXGetGraphicsError(nil); );
  461.  
  462.         SetViewDeviceColorSet(vd, theColorSet);
  463.         require_action( GXGetGraphicsError(nil) == noErr, SetViewDeviceColorSet, anErr = GXGetGraphicsError(nil); );
  464.     
  465.         // Dispose of the reference to the temporary shape
  466.         GXDisposeColorSet(theColorSet);
  467.     }
  468.     
  469.     // Change the viewDevice mapping to include the scaling factor from 72dpi (screen) to 216 dpi (device). 
  470.     {
  471.         ResetMapping(&vdMapping);
  472.         ScaleMapping(&vdMapping, ff(3), ff(3), ff(0), ff(0));
  473.         
  474.         GXSetViewDeviceMapping(vd, &vdMapping);
  475.     }
  476.     
  477.     // Add the newly created viewDevice to the printer object 
  478.  
  479.     anErr = GXAddPrinterViewDevice(thePrinter, vd);
  480.     require_action( GXGetGraphicsError(nil) == noErr, AddPrinterViewDevice, anErr = GXGetGraphicsError(nil); );
  481.     
  482.     return(anErr);
  483.     
  484.     
  485. /******* Clean-up *******/
  486.  
  487. SetViewDeviceColorSet:
  488.     GXDisposeColorSet(theColorSet);
  489.  
  490. AddPrinterViewDevice:
  491. NewColorSet:
  492.     GXDisposeViewDevice(vd);
  493.     return(anErr);
  494.  
  495. NewViewDevice:
  496.     GXDisposeShape(theBitmap);
  497.  
  498. NewBitmap:
  499.     return(anErr);
  500. }
  501. /* MakeNewPrinterViewDevice */
  502.  
  503.  
  504. /****************************************************************************************
  505.  
  506.                             WriteDraftChars
  507.                             
  508.     function:
  509.                 This routine is called to output a single character in the native set of the
  510.                 printer.  The draftTable parameter contains long word entries for each possible
  511.                 character that can be printed.  Each long word entry is composed of two word entries,
  512.                 where the first word represents the primary character to output and the second
  513.                 word optionally specifies an overstrike character.  If an overstrike character
  514.                 is specified, then we will overstrike the second character on the first.  The format
  515.                 of each word is the same and is as follows:
  516.                 
  517.                 bit 15         -    0 => don't backspace before writing character
  518.                                     1 => backspace first before printing the character
  519.                 
  520.                 bits 14:12    -    0
  521.  
  522.                 bits 11:8    -    national character set to invoke (e.g. kAmerican)
  523.  
  524.                 bits 7:0        -    the character to send to the printer (must be != 0 to be output)
  525.                 
  526.     parameters:    
  527.                 draftTable        Handle to an array of long word entries that describe how to output
  528.                                     each printable character in draft mode
  529.                 draftChar        Pointer to the ASCII characters that are to be output
  530.                 numChars            Number of characters to be output
  531.                 
  532.     returns:
  533.                 OSErr
  534.     
  535. ****************************************************************************************/
  536. OSErr WriteDraftChars(long **draftTable, unsigned char *draftChar, long numChars)
  537. {
  538.     OSErr        anErr = noErr;
  539.     char        outputChars[20];                // a maximum of 20 characters can be generated
  540.     short        charCount;                    
  541.     
  542.     // For each character in the buffer, determine how to map the character to a draft character
  543.     for (; numChars > 0; --numChars, ++draftChar)
  544.     {
  545.         // No characters yet for this output character
  546.         charCount = 0;
  547.             
  548.         // Only consider characters in the printable range
  549.         if (*draftChar >= 0x20)
  550.         {
  551.             unsigned long    draftControl = (*draftTable)[*draftChar-0x20];    // Fetch native mode long word corresponding to this character
  552.             unsigned char    outChar;
  553.             unsigned char    nationalSet;
  554.             short                i;
  555.             
  556.             // For each word which composes the native mode long word 
  557.             for (i = 1; i >= 0; --i)
  558.             {
  559.                 // Should we send a backspace character (to overstrike)?
  560.                 if ( (draftControl & 0x80000000) != 0 )
  561.                     outputChars[charCount++] = 0x08;
  562.                 
  563.                 outChar = (draftControl >> 16) & 0xFF;
  564.                 if (outChar != 0)
  565.                 {
  566.                     // Determine the national character set to select
  567.                     nationalSet = (draftControl >> 24) & 0xF;    
  568.     
  569.                     //    Is this character in the standard, built-in character set?
  570.                     if (nationalSet == kAmerican)
  571.                     {
  572.                         outputChars[charCount++] = outChar;
  573.                     }
  574.                     else    //    T => Must select a foreign language character set 
  575.                     {
  576.                         outputChars[charCount++] = 0x1B;
  577.                         outputChars[charCount++] = 0x44;
  578.                         outputChars[charCount++] = nationalSet;
  579.                         outputChars[charCount++] = 0x00;
  580.                         outputChars[charCount++] = outChar;
  581.                         outputChars[charCount++] = 0x1B;                // We always switch back to the kAmerican character set
  582.                         outputChars[charCount++] = 0x5A;
  583.                         outputChars[charCount++] = 0x07;
  584.                         outputChars[charCount++] = 0x00;
  585.                     }
  586.                 }
  587.                 
  588.                 // Take the next (low) word and process it (if we're not all done)
  589.                 draftControl <<= 16;
  590.             }    
  591.         }
  592.             
  593.         // If we generated any data, send it out now
  594.         if (charCount > 0)
  595.             anErr = Send_GXBufferData(outputChars, charCount, gxNoBufferOptions);
  596.     }
  597.         
  598.     return(anErr);    
  599.     
  600. /* WriteDraftChars */
  601.  
  602.  
  603. /****************************************************************************************
  604.  
  605.                             GetPointerThisBig
  606.                             
  607.     function:
  608.                 This routine is called to return a pointer (in the heap) to the number of
  609.                 bytes specified by numBytes.  If the pointer is already large enough, then
  610.                 this routine simply returns the existing pointer.  Otherwise, it allocates
  611.                 a new pointer (possibly disposing of the old one) of the specified size.
  612.                 
  613.     parameters:    
  614.                 theBuff            returns a pointer to the allocated buffer 
  615.                 numBytes            required size of the pointer returned (in bytes)
  616.                 
  617.     returns:
  618.                 OSErr
  619.     
  620. ****************************************************************************************/
  621. OSErr GetPointerThisBig(Ptr *theBuff, long numBytes) 
  622. {
  623.     OSErr        anErr = noErr;
  624.     
  625.     if (*theBuff != nil)
  626.     {
  627.         if ( GetPtrSize(*theBuff) < numBytes )    //    T => Won't be big enough; make a new one
  628.         {
  629.             DisposPtr(*theBuff);
  630.             *theBuff = nil;
  631.         }
  632.     }
  633.  
  634.     if (*theBuff == nil)
  635.     {
  636.         *theBuff = NewPtrClear(numBytes);
  637.         anErr = MemError();
  638.     }
  639.     
  640.     return(anErr);
  641. }
  642. /* GetPointerThisBig */
  643.  
  644.  
  645. /****************************************************************************************
  646.  
  647.                             GetTextAndPosition
  648.                             
  649.     function:
  650.                 This routine is called to return information about the layout shape
  651.                 referenced by the theShape parameter.  It returns a pointer to the
  652.                 text data in theChars, the number of characters in the data in numChars, and
  653.                 a pointer to the positions of the characters in textPositions.  The caller
  654.                 is responsible for disposing of the pointers returned in theChars and
  655.                 textPositions.
  656.                 
  657.     parameters:    
  658.                 theShape            reference to the shape to be examined
  659.                 theChars            returns a pointer to the text characters
  660.                 numChars            returns the number of characters in the text shape
  661.                 textPosition    returns the position of the layout shape
  662.                 
  663.     returns:
  664.                 OSErr
  665.     
  666. ****************************************************************************************/
  667. OSErr GetTextAndPosition(    gxShape            theShape, 
  668.                                     Ptr            *theChars, 
  669.                                     long            *numChars, 
  670.                                     gxPoint            *textPosition)
  671. {
  672.     OSErr        anErr = noErr;
  673.     long        textStrLength;
  674.     
  675.     // Determine the size of the text data and the position of the text
  676.     textStrLength = GXGetLayout(theShape, nil, nil, nil, nil, nil, nil, nil, nil, textPosition);
  677.  
  678.     // Make sure we have a buffer pointer large enough to hold all of the data
  679.     
  680.     anErr = GetPointerThisBig(theChars, textStrLength);
  681.     require(anErr == noErr, CantAllocTextBuff);
  682.     
  683.     // Now we retrieve the text
  684.     GXGetLayout(theShape, *theChars, nil, nil, nil, nil, nil, nil, nil, nil);
  685.     
  686.     // Remember the number of characters in the shape
  687.     *numChars = textStrLength;
  688.     
  689.  
  690. /******* Clean-up *******/
  691.  
  692. CantAllocTextBuff:
  693.     return(anErr);
  694. }
  695. /* GetTextAndPosition */
  696.  
  697.  
  698. /****************************************************************************************
  699.  
  700.                             PrintPageInDraftMode
  701.                             
  702.     function:
  703.                 This routine is called to print a page using the native character set in the
  704.                 printer.  The page to print is referenced by the thePage parameter.  The routine
  705.                 walks through the picture looking for layout shapes.  Each of these
  706.                 shapes is imaged using the native character set; all other shapes are ignored.
  707.                 This routine assumes the shapes within the picture are y-sorted.
  708.                 
  709.     parameters:    
  710.                 thePage        Reference to the page shape that's to be printed
  711.                 imageData    pointer to the raster image data
  712.                 
  713.     returns:
  714.                 OSErr
  715.     
  716. ****************************************************************************************/
  717. OSErr PrintPageInDraftMode(gxShape thePage, gxRasterImageDataHdl imageData)
  718. {
  719.     OSErr                    anErr = noErr;
  720.     long                    i;
  721.     long                    numItems;
  722.     Fixed                    currYPos = ff(0);
  723.     Ptr                    theChars = nil;
  724.     long                    numChars = 0;
  725.     gxPoint                textPosition;
  726.     Fixed                    oldTextSize = ff(0);
  727.     SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  728.     
  729.     // Since the page picture we need to process is a picture shape that's embedded in
  730.     // thePage (a shape containing one item => a picture), we need to extract the real
  731.     // page picture from thePage.
  732.     
  733.     thePage = GetPictureItem(thePage, 1, nil, nil, nil, nil);
  734.     numItems = GXGetPicture(thePage, nil, nil, nil, nil);
  735.     
  736.     // For each shape within the picture, check its type and process it accordingly
  737.     
  738.     for (i = 1; i <= numItems; ++i)
  739.     {
  740.         gxShape                theShape;
  741.         short                    theType;
  742.         
  743.         theShape = GetPictureItem(thePage, i, nil, nil, nil, nil);
  744.         theType = GXGetShapeType(theShape);
  745.         
  746.         if (theType == gxLayoutType)    //    T => We have a layout shape
  747.         {
  748.             Fixed        textSize;
  749.             char        buff[12];
  750.             char        theFace;
  751.             short        cmndBuffSz;
  752.             
  753.             // First determine the style in which we're printing
  754.             
  755.             theFace = GetStyleCommonFace( GXGetShapeStyle(theShape) );
  756.             
  757.             buff[0] = kEscape;
  758.             if ( (theFace & bold) != 0 )    //    T => Turn bold facing on
  759.                 buff[1] = '!';
  760.             else                                    //    T => Turn it off
  761.                 buff[1] = '"';
  762.             
  763.             buff[2] = kEscape;
  764.             if ( (theFace & underline) != 0 )    //    T => Turn underline facing on
  765.                 buff[3] = 'X';
  766.             else                                            //    T => Turn it off
  767.                 buff[3] = 'Y';
  768.                 
  769.             cmndBuffSz = 4;
  770.             
  771.             // Next determine if we need to change the size of the font being used
  772.             
  773.             textSize = GXGetShapeTextSize(theShape);
  774.             if (textSize != oldTextSize)    //    T => Must issue LQ command to change font size
  775.             {
  776.                 buff[4] = kEscape;                //    The first escape command selects black color
  777.                 buff[5] = kSetColorCommand;
  778.                 buff[6] = '0';
  779.                 
  780.                 buff[7] = kEscape;                //    The second escape command selects a draft font
  781.                 buff[8] = 'a';
  782.                 buff[9] = '1';
  783.                 
  784.                 buff[10] = kEscape;                //    The third escape command selects the character pitch
  785.                 
  786.                 if ( textSize <= ff(10) )    //    T => Select 10 cpi
  787.                 {
  788.                     buff[11] = 'N';
  789.                 }
  790.                 else    //    T => All other sizes get mapped to 12 cpi
  791.                 {
  792.                     buff[11] = 'E';
  793.                 }
  794.                 
  795.                 // Remember the last text size
  796.                 oldTextSize = textSize;    
  797.                 
  798.                 // Adjust the size of the data to be sent to the printer
  799.                 cmndBuffSz += 8;
  800.             }
  801.             // else - no change in font size
  802.             
  803.             // Send the commands to the printer
  804.             anErr = Send_GXBufferData(buff, cmndBuffSz, gxDontSplitBuffer);
  805.             require(anErr == noErr, CantSendFontCmnd);
  806.  
  807.             // Get the ASCII text and the starting position of the data
  808.             anErr = GetTextAndPosition(theShape, &theChars, &numChars, &textPosition);
  809.             require(anErr == noErr, CantGetTextAndPos);
  810.             
  811.             if ( (currYPos != ff(0)) && (currYPos != textPosition.y) )    //    T => Moving to a lower line, finish the last ;line with a CR
  812.             {
  813.                 char        c = 0x0D;
  814.                 
  815.                 anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
  816.                 require(anErr == noErr, CantSendCRCmnd);
  817.             }
  818.             
  819.             // Position the print head to the proper location on the page
  820.             {
  821.                 gxMapping            theMapping;
  822.                 long                    lineFeedSize;
  823.                 Str255                positionCmndsBuff;
  824.                 unsigned long        bytesInBuff = 0;
  825.                 char                    *p;
  826.  
  827.                 GXGetShapeMapping(theShape, &theMapping);
  828.                 MapPoints(&theMapping, (long) 1, &textPosition);    //    Just map the first point
  829.                 
  830.                 // Now position the print head vertically
  831.  
  832.                 lineFeedSize = (textPosition.y - currYPos) >> 16;
  833.                 anErr = Send_GXRasterLineFeed(&lineFeedSize, (char *) positionCmndsBuff, &bytesInBuff, imageData);
  834.                 require(anErr == noErr, CantEmitLineFeeds);
  835.                 
  836.                 // Update the current Y position pointer on the page
  837.                 currYPos = textPosition.y;
  838.  
  839.                 // Now position the print head horizontally on the page
  840.  
  841.                 p = (char *) &positionCmndsBuff[bytesInBuff];        
  842.                 *p++ = kEscape;
  843.                 *p++ = kLowResMarginsCommand;
  844.                 Long2Dec((*hGlobals)->leftMargin + FixedToInt(textPosition.x), p);    // Convert left margin into ASCII and place it at the start of the scan line
  845.                 
  846.                 // Update the number of bytes in the buffer
  847.                 bytesInBuff += 6;
  848.  
  849.                 // Send the positioning info to the printer
  850.                 anErr = Send_GXBufferData((char *) positionCmndsBuff, bytesInBuff, gxDontSplitBuffer);
  851.                 require(anErr == noErr, CantSendPositionCmnds);
  852.             }
  853.             
  854.             // Now we send the text data to the printer
  855.             anErr = WriteDraftChars((long **) (*hGlobals)->draftTable, (unsigned char *) theChars, numChars);
  856.             require(anErr == noErr, CantWriteChars);
  857.         }
  858.     }    // for
  859.  
  860.     // Send one last CR to wrap the last line (if there was one)
  861.     {
  862.         char        c = 0x0D;
  863.         
  864.         anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
  865.     }
  866.  
  867.  
  868. /******* Clean-up *******/
  869.  
  870. CantWriteChars:
  871. CantSendPositionCmnds:
  872. CantEmitLineFeeds:
  873. CantSendCRCmnd:
  874. CantGetTextAndPos:
  875. CantSendFontCmnd:
  876.     if (theChars != nil)
  877.         DisposPtr(theChars);
  878.                 
  879.     return(anErr);
  880. }
  881. /* PrintPageInDraftMode */
  882.  
  883.  
  884. /***************************************************************************************
  885. *                                         INTERFACE ROUTINES                                                     *
  886. ***************************************************************************************/                        
  887.  
  888. /****************************************************************************************
  889.  
  890.                             SD_Initialize
  891.                             
  892.     function:
  893.                 This routine is called when a new job is created to perform some job-oriented
  894.                 task, such as conducting dialogs, spooling, and imaging.  It allocates the
  895.                 driver's globals handle and initializes it.
  896.                 
  897.     parameters:    
  898.                 None
  899.                 
  900.     returns:
  901.                 OSErr
  902.     
  903. ****************************************************************************************/
  904. OSErr SD_Initialize(void)
  905. {
  906.     OSErr                 anErr;
  907.     SpecGlobalsHdl     hGlobals;
  908.     
  909.     // Allocate the driver's global handle 
  910.  
  911.     hGlobals = (SpecGlobalsHdl) NewHandleClear(kSpecGlobalsRecLen);
  912.     anErr = MemError();
  913.     require(anErr == noErr, NewHandleClear);
  914.     
  915.     // Tell the Printing Manager to save our globals handle for us 
  916.     SetMessageHandlerInstanceContext(hGlobals);
  917.  
  918.     return(anErr);
  919.     
  920.     
  921. /******* Clean-up *******/
  922.  
  923. NewHandleClear:
  924.     return(anErr);
  925. }
  926. /* SD_Initialize */
  927.  
  928.  
  929. /****************************************************************************************
  930.  
  931.                             SD_ShutDown
  932.                             
  933.     function:
  934.                 This routine is called when a job-oriented task has completed and the 
  935.                 message chain is being destroyed.  This routine disposes of the driver's
  936.                 globals handle..
  937.                 
  938.     parameters:        
  939.                 None
  940.                 
  941.     returns:
  942.                 OSErr
  943.     
  944. ****************************************************************************************/
  945. OSErr SD_ShutDown(void)
  946. {
  947.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  948.     
  949.     // Dump the draft table if we loaded it
  950.     if ( (*hGlobals)->draftTable != nil )
  951.         DisposHandle((*hGlobals)->draftTable);
  952.     
  953.     // Dump the driver's globals handle if it was allocated 
  954.     if (hGlobals != nil)
  955.         DisposHandle((Handle) hGlobals);
  956.  
  957.     // Make sure the Printing Manager no longer has a reference to our globals handle 
  958.     SetMessageHandlerInstanceContext(nil);
  959.         
  960.     return(noErr);
  961. }
  962. /* SD_ShutDown */
  963.  
  964.  
  965. /****************************************************************************************
  966.  
  967.                             SD_JobFormatDialog
  968.                             
  969.     function:
  970.                 This routine is called when the Printing Manager is called to display the
  971.                 Job Format dialog.  This message gives the driver the opportunity to determine
  972.                 the job format modes that are supported by the application.  If the application
  973.                 supports text, then we set the preferred job format mode to be 'text'.  The preferred
  974.                 format mode is the format mode that becomes active when the user selects Direct
  975.                 Mode from the Job Format dialog box.
  976.                 
  977.     parameters:                
  978.                 dlgResult        result of dismissing the dialog (ok or cancel)
  979.                 
  980.     returns:
  981.                 OSErr
  982.                 
  983. ****************************************************************************************/
  984. OSErr SD_JobFormatDialog(gxDialogResult *dlgResult)
  985. {
  986.     OSErr                         anErr;
  987.     gxJobFormatModeTableHdl    theJobFormatModeList;
  988.     gxJob                             theJob = GXGetJob();
  989.     
  990.     // Did the application specify any job format modes?
  991.     
  992.     anErr = GXGetAvailableJobFormatModes(&theJobFormatModeList);
  993.     if ( (anErr == noErr) && (theJobFormatModeList != nil) )
  994.     {
  995.         long    i;
  996.  
  997.         // Examine each job format mode to determine if 'text' mode is supported.  If
  998.         // it is, then we make it the preferred format mode for Direct Mode printing
  999.         
  1000.         for (i = 0; i <= (*theJobFormatModeList)->numModes - 1; ++i) 
  1001.         {
  1002.             if ((*theJobFormatModeList)->modes[i] == gxTextJobFormatMode) 
  1003.             {
  1004.                 // Tell Printing Manger we support 'text' Direct Mode, but that we also
  1005.                 // support other modes.
  1006.                 
  1007.                 GXSetPreferredJobFormatMode(gxTextJobFormatMode, false);
  1008.                 break;
  1009.             }
  1010.         }
  1011.         
  1012.         // Dump the temporary handle we were issued
  1013.         DisposHandle((Handle)theJobFormatModeList);
  1014.     }
  1015.         
  1016.     // New we let the dialog be displayed. 
  1017.  
  1018.     anErr = Forward_GXJobDefaultFormatDialog(dlgResult);
  1019.     require(anErr == noErr, Forward_GXJobFormatDialog);
  1020.     
  1021.     return(anErr);
  1022.     
  1023.     
  1024. /******* Clean-up *******/
  1025.  
  1026. Forward_GXJobFormatDialog:
  1027.     return(anErr);
  1028. }
  1029. /* SD_JobFormatDialog */
  1030.  
  1031.  
  1032. /****************************************************************************************
  1033.  
  1034.                             SD_JobPrintDialog
  1035.                             
  1036.     function:
  1037.                 This routine is called when the Printing Manager is called to display the
  1038.                 Job dialog.  This message gives the driver the opportunity to add the LQ Options
  1039.                 panel to the dialog.  This panel provides the user the option to choose between
  1040.                 bidirectional and unidirectional printing.
  1041.                 
  1042.     parameters:                
  1043.                 dlgResult        result of dismissing the dialog (ok or cancel)
  1044.                 
  1045.     returns:
  1046.                 OSErr
  1047.                 
  1048. ****************************************************************************************/
  1049. OSErr SD_JobPrintDialog(gxDialogResult *dlgResult)
  1050. {
  1051.     OSErr                     anErr;
  1052.     gxPanelSetupRecord    thePanelInfo;
  1053.     long                        headMotionSize;
  1054.     Collection                jobCollection;
  1055.     HeadMotionJobItem        theMotion;
  1056.         
  1057.     // Get a reference to the job's collection
  1058.     jobCollection = GXGetJobCollection( GXGetJob() );
  1059.     
  1060.     // See if the head motion collection item exists.  It the item already exists, then
  1061.     // we'll use the last settings.
  1062.  
  1063.     headMotionSize = sizeof(HeadMotionJobItem);
  1064.     anErr = GetCollectionItem (jobCollection,
  1065.                                         kDrvrCreatorType, 
  1066.                                         kHeadMotionItemIndex, 
  1067.                                            &headMotionSize,
  1068.                                            &theMotion);
  1069.                                         
  1070.     if (anErr == collectionItemNotFoundErr)    // T => Item doesn't exist; add it
  1071.     {
  1072.         theMotion.direction = doUnidirectional;
  1073.         
  1074.         anErr = AddCollectionItem(    jobCollection, 
  1075.                                             kDrvrCreatorType, 
  1076.                                             kHeadMotionItemIndex, 
  1077.                                             sizeof(HeadMotionJobItem),
  1078.                                             &theMotion);
  1079.         require(anErr == noErr, AddCollectionItem);
  1080.     }
  1081.     else
  1082.         require(anErr == noErr, CantGetCollection);
  1083.  
  1084.     // Before allowing the Printing Manager to display the dialog, we must first add
  1085.     // our panel to the dialog.  We do this by appropriately filling in the PanelSetupRecord
  1086.     // and then telling the Printing Manager to add our panel to the dialog.
  1087.     
  1088.     // Initialize the dialog panel structure
  1089.     thePanelInfo.panelResId            = kLQOptionsPanl;        //    Resource ID of the 'panl' resource
  1090.     thePanelInfo.resourceRefNum    = GXGetMessageHandlerResFile();
  1091.     thePanelInfo.refCon                = 0;
  1092.     thePanelInfo.panelKind            = gxDriverPanel;
  1093.     
  1094.     // Add the dialog panel to the Print dialog
  1095.     
  1096.     GXSetupDialogPanel(&thePanelInfo);
  1097.     anErr = GXGetJobError( GXGetJob() );
  1098.     require(anErr == noErr, SetupDialogPanel);
  1099.  
  1100.     // Now we let the dialog be displayed. 
  1101.  
  1102.     anErr = Forward_GXJobPrintDialog(dlgResult);
  1103.     check(anErr == noErr);
  1104.     
  1105.     
  1106. /******* Clean-up *******/
  1107.  
  1108. Forward_GXJobPrintDialog:
  1109. SetupDialogPanel:
  1110. CantGetCollection:
  1111. AddCollectionItem:
  1112.     return(anErr);
  1113. }
  1114. /* SD_JobPrintDialog */
  1115.  
  1116.  
  1117. /****************************************************************************************
  1118.  
  1119.                             SD_JobFormatModeQuery
  1120.                             
  1121.     function:
  1122.                 This routine is called when an application calls JobFormatModeQuery to determine
  1123.                 the format modes that are available from the driver.  This message gives the 
  1124.                 driver the opportunity to determine the type of format mode query the driver
  1125.                 is requesting and responds to it with the appropriate data.
  1126.                 
  1127.     parameters:                
  1128.                 theQuery        type of query to perform
  1129.                 srcData        source data (varies depending upon the type of query)
  1130.                 dstData        destination data (varies depending upon the type of query)
  1131.                 
  1132.     returns:
  1133.                 OSErr
  1134.                 
  1135. ****************************************************************************************/
  1136. OSErr SD_JobFormatModeQuery(gxQueryType theQuery, void *srcData, void *dstData)
  1137. {
  1138.     OSErr        anErr = noErr;
  1139.     Handle    theFonts;
  1140.     Handle    theStyles;
  1141.     
  1142.     check(dstData != nil);
  1143.     
  1144.     // What type of query is being requested?
  1145.     switch(theQuery) 
  1146.     {
  1147.         case gxSetStyleJobFormatCommonStyleQuery:
  1148.         {
  1149.             char                *pStyleName;
  1150.  
  1151.             // Fetch the list of supported styles
  1152.             
  1153.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
  1154.             require(anErr == noErr, FailedToLoadStyles1);
  1155.             
  1156.             HNoPurge(theStyles);
  1157.             HLock(theStyles);
  1158.             
  1159.             // Determine which style is being referenced and set the corresponding style (only 2 styles
  1160.             // are currently supported)
  1161.             
  1162.             if (**((short **) theStyles) == 2)    //    T => We have the correct number of styles
  1163.             {
  1164.                 char        whichFace = 0;
  1165.                 
  1166.                 pStyleName = ((char *) *theStyles) + sizeof(short); 
  1167.                 
  1168.                 if ( IUCompString((unsigned char const *) pStyleName, (unsigned char const *) srcData) == 0 )    //    T => They want bold face
  1169.                 {
  1170.                     whichFace = bold;
  1171.                 }
  1172.                 else
  1173.                 {
  1174.                     // Point to the next name in the list
  1175.                     pStyleName += *pStyleName + 1;
  1176.  
  1177.                     if ( IUCompString((unsigned char const *) pStyleName, (unsigned char const *) srcData) == 0 )    //    T => They want underline face
  1178.                     {
  1179.                         whichFace = underline;
  1180.                     }
  1181.                 }
  1182.  
  1183.                 //    If the client specified a valid face, set it now
  1184.                 if (whichFace != 0)
  1185.                 {
  1186.                     SetStyleCommonFace((gxStyle) dstData, GetStyleCommonFace((gxStyle) dstData) | whichFace);
  1187.                 }
  1188.             }
  1189.             // else - something is wrong with our resource
  1190.             
  1191.             // Dump the temporary handle
  1192.             DisposHandle(theStyles);
  1193.             
  1194.             break;
  1195.         }
  1196.             
  1197.         case gxGetJobFormatFontCommonStylesQuery:
  1198.         {
  1199.             short                numStyles;
  1200.             short                i;
  1201.             char                *pStyleName;
  1202.  
  1203.             // Fetch the list of supported styles
  1204.             
  1205.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
  1206.             require(anErr == noErr, FailedToLoadStyles2);
  1207.             
  1208.             HNoPurge(theStyles);
  1209.             HLock(theStyles);
  1210.             
  1211.             // Determine the number of styles in the list
  1212.             numStyles = **((short **) theStyles);
  1213.  
  1214.             if (*(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on the styles
  1215.                 SetHandleSize(*(Handle *)dstData, sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
  1216.             else
  1217.                 *(Handle *)dstData = NewHandle(sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
  1218.             
  1219.             anErr = MemError();
  1220.             require(anErr == noErr, StyleTableResizeFailed);
  1221.             
  1222.             // Now extract the name of each of the supported fonts
  1223.             
  1224.             for (i = 1, pStyleName = ((char *) *theStyles) + sizeof(short); i <= numStyles; ++i, pStyleName += *pStyleName + 1)
  1225.             {
  1226.                 BlockMove(pStyleName, (*((gxStyleNameTableHdl) *(Handle *)dstData))->styleNames[i - 1], *pStyleName + 1);
  1227.             }
  1228.             
  1229.             (*((gxStyleNameTableHdl) *(Handle *)dstData))->numStyleNames = numStyles;
  1230.             
  1231.             // Dump the temporary handle
  1232.             DisposHandle(theStyles);
  1233.             
  1234.             break;
  1235.         }
  1236.             
  1237.         case gxGetJobFormatLineConstraintQuery:            //    This type of query is not supported
  1238.             if (*(Handle *)dstData != nil)
  1239.                 SetHandleSize(*(Handle *)dstData, 0);        // Don't return any data
  1240.             break;
  1241.             
  1242.         case gxGetJobFormatFontsQuery:
  1243.         {
  1244.             short                numFonts;
  1245.             short                i;
  1246.             char                *pFontName;
  1247.  
  1248.             // Fetch the list of supported fonts
  1249.             
  1250.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeFontsID, &theFonts);
  1251.             require(anErr == noErr, FailedToLoadFonts);
  1252.             
  1253.             HNoPurge(theFonts);
  1254.             HLock(theFonts);
  1255.             
  1256.             // Determine the number of fonts in the list
  1257.             numFonts = **((short **) theFonts);
  1258.  
  1259.             if (*(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on the fonts
  1260.                 SetHandleSize(*(Handle *)dstData, sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
  1261.             else
  1262.                 *(Handle *)dstData = NewHandle(sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
  1263.             
  1264.             anErr = MemError();
  1265.             require(anErr == noErr, FontTableResizeFailed);
  1266.             
  1267.             // Now generate a reference to each of the supported fonts
  1268.             
  1269.             for (i = 1, pFontName = ((char *) *theFonts) + sizeof(short); i <= numFonts; ++i, pFontName += *pFontName + 1)
  1270.             {
  1271.                 gxFont            thisFont;
  1272.                 gxFontTable    *pFontTable;
  1273.             
  1274.                 thisFont = FindPNameFont(gxFullFontName, (unsigned char const *) pFontName);
  1275.                 
  1276.                 pFontTable = *((gxFontTableHdl) *(Handle *)dstData);
  1277.                 pFontTable->fonts[i - 1] = thisFont;
  1278.             }
  1279.             
  1280.             (*((gxFontTableHdl) *(Handle *)dstData))->numFonts = numFonts;
  1281.             
  1282.             // Dump the temporary handle
  1283.             DisposHandle(theFonts);
  1284.  
  1285.             break;
  1286.         }
  1287.             
  1288.         case gxGetJobFormatFontConstraintQuery:
  1289.         {
  1290.             gxPositionConstraintTable        *pPositionTable;
  1291.             
  1292.             if ( *(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on position constraints
  1293.                 SetHandleSize(*(Handle *)dstData, sizeof(gxPositionConstraintTable) + sizeof(Fixed));
  1294.             else
  1295.                 *(Handle *)dstData = NewHandle( sizeof(gxPositionConstraintTable) + sizeof(Fixed) );
  1296.             
  1297.             pPositionTable = *((gxPositionConstraintTableHdl) *(Handle *)dstData);
  1298.             
  1299.             pPositionTable->phase.x     = 0;                //    Start at the top left corner of the page
  1300.             pPositionTable->phase.y     = 0;
  1301.             pPositionTable->offset.x     = ff(12);        // Indent from the top left by a six lines per inch margin
  1302.             pPositionTable->offset.y     = ff(12);         
  1303.             pPositionTable->numSizes     = 2;                // Two font sizes supported
  1304.             pPositionTable->sizes[0]     = ff(10);         // 10 pitch
  1305.             pPositionTable->sizes[1]     = ff(12);         // 12 pitch
  1306.             
  1307.             break;
  1308.         }
  1309.     } // switch
  1310.     
  1311.     return(anErr);
  1312.     
  1313.  
  1314. /******* Clean-up *******/
  1315.  
  1316. StyleTableResizeFailed:
  1317.     DisposHandle((Handle) theStyles);
  1318.     return(anErr);
  1319.  
  1320. FontTableResizeFailed:
  1321.     DisposHandle((Handle) theFonts);
  1322.  
  1323. FailedToLoadStyles1:
  1324. FailedToLoadStyles2:
  1325. FailedToLoadFonts:
  1326.     return(anErr);
  1327. }
  1328. /* SD_JobFormatModeQuery */
  1329.  
  1330.  
  1331. /****************************************************************************************
  1332.  
  1333.                             SD_OpenConnection
  1334.                             
  1335.     function:
  1336.                 This routine is called when the Printing Manager sends the OpenConnection
  1337.                 message.  We take this opportunity to open a connection to the printer and
  1338.                 query the printer to determine its configuration (e.g. color ribbon, trays, etc.).
  1339.                 We then save the configuration information in the desktop printer file.
  1340.                 
  1341.     parameters:        
  1342.                 None
  1343.                 
  1344.     returns:
  1345.                 OSErr
  1346.     
  1347. ****************************************************************************************/
  1348. OSErr SD_OpenConnection(void)
  1349. {
  1350.     OSErr                anErr;
  1351.  
  1352.     // Try to open the connection
  1353.     
  1354.     anErr = Forward_GXOpenConnection();
  1355.     require(anErr == noErr, Forward_GXOpenConnection);
  1356.     
  1357.     // Query the printer so we can update the configuration information
  1358.     
  1359.     anErr = UpdateDTPConfigInfo();
  1360.     require(anErr == noErr, UpdateDTPConfigInfo);
  1361.     
  1362.     return(anErr);
  1363.     
  1364.     
  1365. /******* Clean-up *******/
  1366.  
  1367. UpdateDTPConfigInfo:
  1368.     Send_GXCleanupOpenConnection();
  1369.     
  1370. Forward_GXOpenConnection:
  1371.     return(anErr);
  1372. }
  1373. /* SD_OpenConnection */
  1374.  
  1375.  
  1376. /****************************************************************************************
  1377.  
  1378.                             SD_CleanupOpenConnection
  1379.                             
  1380.     function:
  1381.                 This routine is called when the Printing Manager sends the CleanupOpenConnection
  1382.                 message.  It's initiated by our SD_OpenConnection routine when we cannot query
  1383.                 the printer after opening the connection.  We simply forward the message along to
  1384.                 allow others in the message chain to cleanup.
  1385.                 
  1386.     parameters:        
  1387.                 None
  1388.                 
  1389.     returns:
  1390.                 OSErr
  1391.     
  1392. ****************************************************************************************/
  1393. void SD_CleanupOpenConnection(void)
  1394. {
  1395.     // Just forward along the message
  1396.     Forward_GXCleanupOpenConnection();
  1397. }
  1398. /* SD_CleanupOpenConnection */
  1399.  
  1400.  
  1401. /****************************************************************************************
  1402.  
  1403.                             SD_StartSendPage
  1404.                             
  1405.     function:
  1406.                 This routine is called by the Printing Manager to signal the start of sending
  1407.                 a new page to the printer.  If it's a manual feed job, then we alert the user
  1408.                 to make sure the paper is in the printer.  If the printer has trays attached,
  1409.                 then this routine determines from which tray to feed the paper and then sends
  1410.                 the appropriate tray selection command to the printer.  The tray to pull the
  1411.                 paper from has already been determined by this time by the Universal Driver.
  1412.                 The Job collection contains the index of the tray to pull from.
  1413.                 
  1414.     parameters:                
  1415.                 pageFormat        format for the page to print
  1416.  
  1417.     returns:
  1418.                 OSErr
  1419.     
  1420. ****************************************************************************************/
  1421. OSErr SD_StartSendPage (gxFormat pageFormat)
  1422. {
  1423.     OSErr                    anErr;
  1424.     Collection            jobCollection;
  1425.     gxStatusRecord        *pStatus;
  1426.     gxTrayFeedInfo        trayFeedInfo;
  1427.     long                    itemSize = sizeof(trayFeedInfo);
  1428.     SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  1429.     
  1430.     // Get a reference to the job's collection
  1431.     jobCollection = GXGetJobCollection( GXGetJob() );
  1432.     
  1433.     // Determine if this is a manual feed page 
  1434.  
  1435.     anErr = GetCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
  1436.     nrequire(anErr, GetCollectionItem);
  1437.     
  1438.     if (trayFeedInfo.manualFeedThisPage)    //    T => Alert the user to place the paper into the printer
  1439.     {
  1440.         gxManualFeedRecord    *mfeedInfo;
  1441.         gxPaperType                thePaperType;
  1442.  
  1443.         // Wait for all IO to complete, so that we can correctly tell the user what to do.
  1444.         // Since the WriteData message makes sure all data is flushed before performing the
  1445.         // IO, this call insures that pending IO is complete.
  1446.  
  1447.         anErr = Send_GXWriteData(nil, 0);
  1448.         nrequire(anErr, FlushAllData);
  1449.  
  1450.         // Now we set-up to alert the user to put paper into the printer
  1451.     
  1452.         pStatus = (gxStatusRecord *) NewPtrClear(sizeof(gxStatusRecord) + sizeof(gxManualFeedRecord));
  1453.         anErr = MemError();
  1454.         require(anErr == noErr, NewPtrClear);
  1455.     
  1456.         // Initialize the appropriate fields within the status record 
  1457.         
  1458.         pStatus->statusOwner        = 'univ';
  1459.         pStatus->statResId         = gxUnivAlertStatusResourceId;
  1460.         pStatus->statResIndex     = gxUnivManualFeedIndex;
  1461.         pStatus->bufferLen         = sizeof(gxManualFeedRecord);
  1462.  
  1463.         mfeedInfo = (gxManualFeedRecord *) &pStatus->statusBuffer;
  1464.         mfeedInfo->canAutoFeed = true;
  1465.         GXGetPaperTypeName(thePaperType = GXGetFormatPaperType(pageFormat), mfeedInfo->paperTypeName);
  1466.  
  1467.         // Now display the alert to the user. Continue alerting until the user clicks OK, he cancels
  1468.         // printing, or some other fatal error happens
  1469.         do
  1470.         {
  1471.             // Issue the alert to the user
  1472.             anErr = GXAlertTheUser(pStatus);
  1473.         }
  1474.         while ( (anErr == noErr) && (pStatus->dialogResult == 0) );
  1475.         
  1476.         // Based upon the users response, we continue, cancel, or switch to auto-feed
  1477.         
  1478.         switch (pStatus->dialogResult)
  1479.         {
  1480.             case ok:                        // Assume the user loaded the paper 
  1481.                 break;
  1482.                 
  1483.             case cancel:                // User cancelled the job; make sure the error code is set
  1484.                 anErr = gxPrUserAbortErr;
  1485.                 break;
  1486.                 
  1487.             case gxAutoFeedButtonId:    // User wishes to do the remainder of the job with auto-feed. Update job to 
  1488.                                             // reflect auto-feed. 
  1489.                 
  1490.                 {
  1491.                 gxPaperFeedInfo paperFeed;
  1492.                 
  1493.                 /* Update for job */
  1494.                 paperFeed.autoFeed = true;
  1495.                 (void) AddCollectionItem(jobCollection, gxPaperFeedTag, gxPrintingTagID, sizeof(paperFeed), &paperFeed);
  1496.                 }
  1497.                 
  1498.                 /* Update as it may be reused */
  1499.                 trayFeedInfo.manualFeedThisPage = false;    /* Other trayInfo fields are still valid */
  1500.                 (void) AddCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, sizeof(trayFeedInfo), &trayFeedInfo);
  1501.                 
  1502.                 /* Can pass paper type reference as this IS device communication time */
  1503.                 anErr = Send_GXCheckStatus((Ptr) &thePaperType, sizeof(thePaperType), 0, 'univ');
  1504.                 ncheck(anErr);
  1505.                 
  1506.                 /* Update gxTrayFeedInfo.feedTrayIndex for below */
  1507.                 itemSize = sizeof(trayFeedInfo);
  1508.                 if (! anErr)
  1509.                     anErr = GetCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
  1510.                 break;
  1511.         }
  1512.         
  1513.         // Dump the status record
  1514.         DisposPtr((Ptr) pStatus);
  1515.     }
  1516.     
  1517.     require(anErr == noErr, UserAborted);
  1518.     
  1519.     // At this point we determine if there are trays attached, and if so, we need
  1520.     // to issue a command to the printer to select from the proper tray.
  1521.     
  1522.     if ( PrinterHasTrays() > 0 )    //    T => Printer does have trays attached
  1523.     {
  1524.         gxTrayIndex                whichTray;
  1525.         char                        cmndBuff[3];
  1526.         TraySettingsJobItem    oldAppTraySettings;
  1527.         
  1528.         // We first determine if we're printing from an old application or a new application because
  1529.         // the setting of which tray to use will be determined from different information. To see if
  1530.         // we are printing an old app. document, we look for the kTraySettingsItemIndex collection item.
  1531.         
  1532.         itemSize = sizeof(TraySettingsJobItem);
  1533.         if ( GetCollectionItem( GXGetJobCollection(GXGetJob()), kDrvrCreatorType, kTraySettingsItemIndex, &itemSize, &oldAppTraySettings) == noErr )
  1534.         {
  1535.             if ( (*hGlobals)->pagePrinting == 1 )    //    T => Printing the first page
  1536.             {
  1537.                 whichTray = oldAppTraySettings.firstPageFromTray - 1;        //    Must be zero based
  1538.             }
  1539.             else    //    T => Printing some other page
  1540.             {
  1541.                 whichTray = oldAppTraySettings.remainingFromTray - 1;        //    Must be zero based
  1542.             }
  1543.         }
  1544.         else    //    T => New app so get tray settings from the 'tray' collection item
  1545.         {
  1546.             // The trayFeedInfo specifies which tray to select the paper from.
  1547.             whichTray = trayFeedInfo.feedTrayIndex - 1;        // Must be zero based
  1548.         }
  1549.         
  1550.         // Compose the tray selection command
  1551.         
  1552.         cmndBuff[0] = kEscape;
  1553.         cmndBuff[1] = '@';
  1554.         cmndBuff[2] = whichTray + 0x30;        // Force to an ACSII number
  1555.         
  1556.         // Send the command to the printer
  1557.         anErr = Send_GXBufferData(cmndBuff, 3, gxNoBufferOptions);
  1558.         require(anErr == noErr, BufferData);        
  1559.     }
  1560.     
  1561.     // Update the status information to tell the user that we're sending data to the printer
  1562.     
  1563.     anErr = GXReportStatus(kDriverStatusID, kSendingPartOfPageStatIdx);
  1564.     require(anErr == noErr, ReportStatus);
  1565.  
  1566.     // Now forward the message to others in the chain
  1567.     
  1568.     anErr = Forward_GXStartSendPage(pageFormat);
  1569.     check(anErr == noErr);
  1570.     
  1571.     
  1572. /******* Cleanup *******/
  1573.  
  1574. ReportStatus:
  1575. BufferData:
  1576. UserAborted:
  1577. NewPtrClear:
  1578. FlushAllData:
  1579. GetCollectionItem:
  1580.     return(anErr);
  1581. }
  1582. /* SD_StartSendPage */
  1583.  
  1584.  
  1585. /****************************************************************************************
  1586.  
  1587.                             SD_ImagePage
  1588.                             
  1589.     function:
  1590.                 This routine is called by the Printing Manager to signal the start of imaging
  1591.                 a new page to the printer.  We take this opportunity to remember which page is
  1592.                 being printed.  This inforamtion is later used by SD_StartSendPage to control
  1593.                 the input tray selection for documents which are printed from old applications.
  1594.                 
  1595.     parameters:                
  1596.                 theFormat        format for the page being rendered
  1597.                 theShape            shape representing the page
  1598.                 pageInfo            information about the page being rendered
  1599.                 imageData        pointer to the raster image data
  1600.  
  1601.     returns:
  1602.                 OSErr
  1603.     
  1604. ****************************************************************************************/
  1605. OSErr SD_ImagePage (    gxSpoolFile                theFile, 
  1606.                             long                         pageNumber, 
  1607.                             gxFormat                    theFormat, 
  1608.                             gxRasterImageDataHdl    imageData)
  1609. {
  1610.     OSErr                    anErr;
  1611.     SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  1612.  
  1613.     // Remember which page of the document we're currently imaging
  1614.     (*hGlobals)->pagePrinting = pageNumber;
  1615.     
  1616.     // Send the message along to others in the chain
  1617.     anErr = Forward_GXImagePage(theFile, pageNumber, theFormat, imageData);
  1618.     check(anErr == noErr);
  1619.     
  1620.     return(anErr);
  1621. }
  1622. /* SD_ImagePage */
  1623.  
  1624.  
  1625. /****************************************************************************************
  1626.  
  1627.                             SD_RenderPage
  1628.                             
  1629.     function:
  1630.                 This routine is called by the Printing Manager to signal the start of sending
  1631.                 a new page to the printer.  If it's a manual feed job, then we alert the user
  1632.                 to make sure the paper is in the printer.  Next we set the printer's left margin
  1633.                 and then we're set to begin printing the page.
  1634.                 
  1635.     parameters:                
  1636.                 theFormat        format for the page being rendered
  1637.                 theShape            shape representing the page
  1638.                 pageInfo            information about the page being rendered
  1639.                 imageData        pointer to the raster image data
  1640.  
  1641.     returns:
  1642.                 OSErr
  1643.     
  1644. ****************************************************************************************/
  1645. OSErr SD_RenderPage (gxFormat                        theFormat, 
  1646.                             gxShape                        thePage, 
  1647.                             gxPageInfoRecord            *pageInfo, 
  1648.                             gxRasterImageDataHdl     imageData)
  1649. {
  1650.     OSErr                    anErr;
  1651.     SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  1652.     gxRectangle            paperSize;
  1653.     
  1654.     // Find out how big our paper is
  1655.     GXGetFormatDimensions(theFormat, nil, &paperSize);
  1656.     
  1657.     // Determine the left margin (in pixels)
  1658.     {
  1659.         SpecGlobalsPtr            pGlobals;
  1660.         gxRasterImageDataPtr    pImageData;
  1661.  
  1662.         pImageData = *imageData;
  1663.         pGlobals = *hGlobals;
  1664.         if ( -(paperSize.left) < ff(18) )    // T => IW LQ's can't go tighter than .25 inch
  1665.             paperSize.left = -(ff(18));        
  1666.         
  1667.         pGlobals->leftMargin = FixedToInt( FixMul(-paperSize.left, FixDiv(pImageData->hImageRes, ff(72)) ) );
  1668.     }
  1669.  
  1670.     // If not text mode, image the page the normal raster way (via SD_RasterPackageBitmap).  We
  1671.     // must however set the size of the page and position the paper (with line feeds) to get to
  1672.     // the proper "top-of-form".
  1673.     
  1674.     if ( GXGetJobFormatMode(GXGetJob()) != gxTextJobFormatMode ) 
  1675.     {
  1676.         Str255            formStrLength;            // should be more than big enough for form skipping
  1677.         char                aNumber[8];
  1678.         char                len = 0;
  1679.         short                formLen;                // form length (in 144 dpi)
  1680.         short                i;
  1681.         
  1682.         // Force the current line position to be the top of form (assumes the user has positioned the 
  1683.         // paper properly by this time)
  1684.         
  1685.         formStrLength[len++] = kEscape;
  1686.         formStrLength[len++] = 'v';
  1687.  
  1688.         // Now we want to skip down the page past the top margin.  This will put us in a position to
  1689.         // output the first bands of data.
  1690.         
  1691.         formLen = FixedToInt( FixMul(-paperSize.top, ff(2)) );                    // length is set in 144 dpi
  1692.         if (formLen > 0)
  1693.         {
  1694.             // send multiples of 99 since this is the maximum line feed spacing we can have
  1695.             if (formLen >= 99)
  1696.             {
  1697.                 formStrLength[len++] = kEscape;
  1698.                 formStrLength[len++] = 'T';
  1699.                 formStrLength[len++] = '9';
  1700.                 formStrLength[len++] = '9';
  1701.                 do
  1702.                 {
  1703.                     formStrLength[len++] = kLineFeed;        // line feed
  1704.                     
  1705.                     formLen -= 99;
  1706.                 }
  1707.                 while (formLen >= 99);
  1708.             }
  1709.                 
  1710.             // Send remaining line feeds to position to the top of the printable page
  1711.             if (formLen > 0)
  1712.             {
  1713.                 formStrLength[len++] = kEscape;
  1714.                 formStrLength[len++] = 'T';
  1715.                 NumToString(formLen, (unsigned char *) aNumber);
  1716.                 if ( StrLength(aNumber) == 1 )
  1717.                 {
  1718.                     formStrLength[len++] = '0';
  1719.                     formStrLength[len++] = aNumber[1];
  1720.                 }
  1721.                 else
  1722.                 {
  1723.                     formStrLength[len++] = aNumber[1];
  1724.                     formStrLength[len++] = aNumber[2];
  1725.                 }
  1726.                 formStrLength[len++] = kLineFeed;        // line feed
  1727.             }
  1728.         }
  1729.         
  1730.         // Now we must specify the paper length based upon the paper size asociated with the format
  1731.         
  1732.         formStrLength[len++] = kEscape;
  1733.         formStrLength[len++] = 'H';
  1734.  
  1735.         formLen = FixedToInt( FixMul(paperSize.bottom - paperSize.top, ff(2)) );    // length is set in 144 dpi
  1736.         NumToString(formLen, (unsigned char *) aNumber);
  1737.         for (i = 0; i < 4-aNumber[0]; ++i)
  1738.             formStrLength[len++] = '0';
  1739.         for (i = 1; i <= aNumber[0]; ++i)
  1740.             formStrLength[len++] = aNumber[i];
  1741.  
  1742.         // Send out the line feeds and the paper size specifier
  1743.         anErr = Send_GXBufferData((char *) &formStrLength[0], len, gxNoBufferOptions);
  1744.         require(anErr == noErr, SetFormStrLength);        
  1745.     
  1746.         // Now forward the message to others in the chain
  1747.         
  1748.         anErr = Forward_GXRenderPage(theFormat, thePage, pageInfo, imageData);
  1749.         require(anErr == noErr, Forward_GXRenderPage);
  1750.     } 
  1751.     else    //    T => Doing draft (i.e. direct mode) print job; we do all the rendering
  1752.     {
  1753.         anErr = PrintPageInDraftMode(thePage, imageData);
  1754.     }
  1755.     
  1756.     
  1757. /******* Cleanup *******/
  1758.  
  1759. SetFormStrLength:
  1760. Forward_GXRenderPage:
  1761.     return(anErr);
  1762. }
  1763. /* SD_RenderPage */
  1764.  
  1765.  
  1766. /****************************************************************************************
  1767.  
  1768.                             SD_DefaultPrinter
  1769.                             
  1770.     function:
  1771.                 This routine is called when a new printer object is being created as a
  1772.                 result of someone having called NewJob.  This message gives the driver the
  1773.                 opportunity to add any information we want to the new printer object.  In
  1774.                 this case, we add a new black and white viewDevice to the printer object 
  1775.                 which will allow the client application to format a document for this 
  1776.                 specific device at 216 dpi.  If the printer has a color ribbon attachment,
  1777.                 then we create a second view device at 216 dpi which supports eight
  1778.                 colors.
  1779.                 
  1780.     parameters:                
  1781.                 thePrinter        the newly allocated printer object
  1782.                 
  1783.     returns:
  1784.                 OSErr
  1785.                 
  1786. ****************************************************************************************/
  1787. OSErr SD_DefaultPrinter(gxPrinter thePrinter)
  1788. {
  1789.     OSErr             anErr;
  1790.     gxSetColor        theColors[8];
  1791.     gxSetColor        *pColor;
  1792.     
  1793.     // First we let others in the chain default the printer object before we do. 
  1794.  
  1795.     anErr = Forward_GXDefaultPrinter(thePrinter);
  1796.     require(anErr == noErr, Forward_GXDefaultPrinter);
  1797.     
  1798.     // Add the standard black and white view device to the printer object
  1799.     
  1800.     // First set up the color set
  1801.     pColor = &theColors[0];
  1802.     pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0xFFFF;            // white 
  1803.     pColor++;
  1804.     pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;            // black 
  1805.     
  1806.     // Now add the view device
  1807.     anErr = MakeNewPrinterViewDevice(thePrinter, theColors, 2);
  1808.     require(anErr == noErr, MakeBWViewDevice);
  1809.     
  1810.     // Does the printer have a color ribbon installed?
  1811.     if ( PrinterHasColorRibbon() )
  1812.     {
  1813.         // Add the standard color view device to the printer object
  1814.         
  1815.         // First set up the color set
  1816.         //
  1817.         //    Color            Index        R                G                B
  1818.         //    white            0            0xFFFF        0xFFFF        0xFFFF        
  1819.         //    yellow        1            0xFFFF        0xFFFF        0x0000
  1820.         //    magenta        2            0xFFFF        0x0000        0xFFFF
  1821.         //    red            3            0xFFFF        0x0000        0x0000
  1822.         //    cyan            4            0x0000        0xFFFF        0xFFFF
  1823.         //    green            5            0x0000        0xFFFF        0x0000
  1824.         //    blue            6            0x0000        0x0000        0xFFFF
  1825.         //    black            7            0x0000        0x0000        0x0000
  1826.  
  1827.         pColor = &theColors[0];
  1828.         pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0xFFFF;                pColor++;        // white 
  1829.         pColor->rgb.red = pColor->rgb.green = 0xFFFF; pColor->rgb.blue = 0x0000;    pColor++;        // yellow 
  1830.         pColor->rgb.red = pColor->rgb.blue = 0xFFFF; pColor->rgb.green = 0x0000;    pColor++;        // magenta 
  1831.         pColor->rgb.red =0xFFFF;  pColor->rgb.blue = pColor->rgb.green = 0x0000;    pColor++;        // red 
  1832.         pColor->rgb.green = pColor->rgb.blue = 0xFFFF; pColor->rgb.red = 0x0000;    pColor++;        // cyan 
  1833.         pColor->rgb.red = pColor->rgb.blue = 0x0000; pColor->rgb.green = 0xFFFF;    pColor++;        // green 
  1834.         pColor->rgb.red = pColor->rgb.green = 0x0000; pColor->rgb.blue = 0xFFFF;    pColor++;        // blue 
  1835.         pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;                                    // black 
  1836.         
  1837.         // Now add the view device
  1838.         anErr = MakeNewPrinterViewDevice(thePrinter, theColors, 8);
  1839.         require(anErr == noErr, MakeColorViewDevice);
  1840.     }
  1841.     
  1842. /******* Clean-up *******/
  1843.  
  1844. MakeColorViewDevice:
  1845. MakeBWViewDevice:
  1846. Forward_GXDefaultPrinter:
  1847.     return(anErr);
  1848. }
  1849. /* SD_DefaultPrinter */
  1850.  
  1851. /****************************************************************************************
  1852.  
  1853.                             SD_DefaultFormat
  1854.                             
  1855.     function:
  1856.                 This routine is called when a new format is being created as a result of someone
  1857.                 having called NewFormat.  It is also called to sync up the viewDevices with the
  1858.                 collection's quality mode.
  1859.                 
  1860.     parameters:                
  1861.                 theFormat        the format being defaulted
  1862.                 
  1863.     returns:
  1864.                 OSErr
  1865.                 
  1866. ****************************************************************************************/
  1867. OSErr SD_DefaultFormat(gxFormat theFormat)
  1868. {
  1869.     OSErr                anErr;
  1870.     Handle             jobQualitySettingsHdl;    
  1871.     
  1872.     anErr = Forward_GXDefaultFormat(theFormat);
  1873.     
  1874.     // now, if the application has set up a special formatting mode, we need to update
  1875.     // the quality mode collection item (and any private ones we use)
  1876.     if (anErr == noErr)
  1877.         {
  1878.         gxPoint                    dpiPoint;
  1879.         gxMapping                vdMapping;
  1880.         gxViewDevice            selectedDevice = GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 0);
  1881.         
  1882.         dpiPoint.x = ff(72);
  1883.         dpiPoint.y = ff(72);
  1884.         
  1885.         if (selectedDevice != GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 1) )
  1886.             {
  1887.             GXGetViewDeviceMapping(selectedDevice, &vdMapping);
  1888.             MapPoints(&vdMapping, 1, &dpiPoint);
  1889.             
  1890.             {
  1891.             gxQualityInfo        *qualitySettings;
  1892.             Collection            jobCollection = GXGetJobCollection(GXGetJob());
  1893.     
  1894.             jobQualitySettingsHdl = NewHandle(0);
  1895.             anErr = MemError();
  1896.             nrequire(anErr, FailedNewHandle);
  1897.  
  1898.             anErr = GetCollectionItemHdl (     jobCollection,
  1899.                                                         gxQualityTag,
  1900.                                                          gxPrintingTagID,
  1901.                                                        jobQualitySettingsHdl );
  1902.  
  1903.             if (anErr == collectionItemNotFoundErr) 
  1904.                 {
  1905.                 Str255            bestString, roughString;
  1906.                 Size                count1, count2;
  1907.                 Ptr                p;
  1908.         
  1909.                 GetIndString( bestString, kQualityID, kBestString);
  1910.                 GetIndString( roughString, kQualityID, kRoughString);
  1911.  
  1912.                 SetHandleSize(jobQualitySettingsHdl,(sizeof(gxQualityInfo) + bestString[0] + roughString[0] + 2 ));
  1913.                 anErr = MemError();
  1914.                 nrequire( anErr, FailedSetHandleSize );
  1915.                         
  1916.                 qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
  1917.                 
  1918.                 qualitySettings->disableQuality = false;
  1919.                 qualitySettings->defaultQuality = 1;
  1920.                 qualitySettings->currentQuality = 1;
  1921.                 qualitySettings->qualityCount = 2;
  1922.         
  1923.                 count1 = bestString[0]+1;
  1924.                 p = qualitySettings->qualityNames;
  1925.                 BlockMove( bestString, p, count1 );
  1926.         
  1927.                 count2 = roughString[0]+1;
  1928.                 p += count1;
  1929.                 BlockMove( roughString, p, count2 );
  1930.         
  1931.                 }
  1932.             else
  1933.                 qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
  1934.  
  1935.             qualitySettings->currentQuality = 
  1936.                 (dpiPoint.y > ff(200)) ? (qualitySettings->qualityCount-1) : 0;
  1937.  
  1938.             anErr = AddCollectionItemHdl (     jobCollection,
  1939.                                                         gxQualityTag,
  1940.                                                         gxPrintingTagID,
  1941.                                                         jobQualitySettingsHdl );
  1942.                                                  
  1943.             if (anErr == noErr)
  1944.                 (void) SetCollectionItemInfo(jobCollection, gxQualityTag, gxPrintingTagID, 0x0000FFFF, gxVolatileOutputDriverCategory);
  1945.                 
  1946.             DisposHandle(jobQualitySettingsHdl);
  1947.             }
  1948.             
  1949.             }
  1950.  
  1951.         }
  1952.         
  1953. FailedNewHandle:        
  1954.     return(anErr);
  1955.  
  1956. FailedSetHandleSize:
  1957.     DisposHandle(jobQualitySettingsHdl);
  1958.     return(anErr);
  1959.     
  1960. /* SD_DefaultFormat */
  1961.  
  1962. /****************************************************************************************
  1963.  
  1964.                             SD_DefaultJob
  1965.                             
  1966.     function:
  1967.                 This routine is called when a new job is being created as a result of someone
  1968.                 having called NewJob.  The driver takes this opportunity to add a default
  1969.                 head motion collection item to the job.
  1970.                 
  1971.     parameters:                
  1972.                 theJob        the job being defaulted
  1973.                 
  1974.     returns:
  1975.                 OSErr
  1976.                 
  1977. ****************************************************************************************/
  1978. OSErr SD_DefaultJob()
  1979. {
  1980.     OSErr        anErr;
  1981.     gxJob     theJob = GXGetJob();
  1982.     
  1983.     // First forward the default job message along
  1984.     anErr = Forward_GXDefaultJob();
  1985.     require(anErr == noErr, Forward_GXDefaultJob);
  1986.     
  1987.     // Add the default collection item which specifies the desired head motion.
  1988.     {
  1989.         HeadMotionJobItem        theMotion;
  1990.         
  1991.         theMotion.direction = doUnidirectional;
  1992.         
  1993.         anErr = AddCollectionItem(    GXGetJobCollection(theJob), 
  1994.                                             kDrvrCreatorType, 
  1995.                                             kHeadMotionItemIndex, 
  1996.                                             sizeof(HeadMotionJobItem),
  1997.                                             &theMotion);
  1998.         check(anErr == noErr);
  1999.     }
  2000.  
  2001.  
  2002. /******* Clean-up *******/
  2003.  
  2004. Forward_GXDefaultJob:
  2005.     return(anErr);
  2006. }
  2007. /* SD_DefaultJob */
  2008.  
  2009.  
  2010. /****************************************************************************************
  2011.  
  2012.                             SD_SetupImageData
  2013.                             
  2014.     function:
  2015.                 This routine is called when the Printing Manager wants us to initialize any
  2016.                 constant data that's used to image the entire job.  This driver takes this
  2017.                 opportunity to massage the raster image data 
  2018.                 
  2019.     parameters:                
  2020.                 hImageData        Handle to the raster imaging data
  2021.     returns:
  2022.                 OSErr
  2023.     
  2024. ****************************************************************************************/
  2025. OSErr SD_SetupImageData(gxRasterImageDataHdl hImageData)
  2026. {
  2027.     OSErr                        anErr;
  2028.     Boolean                     isJobNotFinalQuality;
  2029.     Boolean                    isTextJobFormatMode;
  2030.     gxRasterImageDataPtr    pImageData;
  2031.     HeadMotionJobItem        theMotion;
  2032.     long                        headMotionSize;
  2033.     gxJob                        theJob = GXGetJob();
  2034.  
  2035.     // Let others in the message chain do their SetupImageData function 
  2036.     anErr = Forward_GXSetupImageData(hImageData);
  2037.     require(anErr == noErr, Forward_GXSetupImageData);
  2038.     
  2039.     // Determine if we're to do "final" quality
  2040.     isJobNotFinalQuality = !JobIsBestQuality();
  2041.     
  2042.     // Fetch the head motion job collection item to determine the head motion we should be using
  2043.  
  2044.     headMotionSize = sizeof(HeadMotionJobItem);
  2045.     anErr = GetCollectionItem (GXGetJobCollection(theJob),
  2046.                                         kDrvrCreatorType,
  2047.                                         kHeadMotionItemIndex,
  2048.                                         &headMotionSize,
  2049.                                         &theMotion);
  2050.     check(anErr == noErr);
  2051.     
  2052.     if (anErr != noErr)    //    T => Default to unidirectional printing => better quality
  2053.     {
  2054.         theMotion.direction = doUnidirectional;
  2055.         anErr = noErr;
  2056.     }
  2057.  
  2058.     // Determine if we are to perform draft mode printing
  2059.     isTextJobFormatMode = ( GXGetJobFormatMode(theJob) == gxTextJobFormatMode );
  2060.     
  2061.     // If the job is not final quality or using textJobFormatMode, downgrade the imaging data to lower quality
  2062.     if (isJobNotFinalQuality || isTextJobFormatMode)
  2063.     {
  2064.         pImageData = *hImageData;
  2065.                 
  2066.         // Image at 72 dpi
  2067.         pImageData->hImageRes = ff(72);
  2068.         pImageData->vImageRes = ff(72);
  2069.         
  2070.         // If we're in draft mode, we need to load the draft table to know how to print all possible characters
  2071.         if (isTextJobFormatMode)
  2072.         {
  2073.             Handle                draftTable;
  2074.             SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  2075.         
  2076.             anErr = Send_GXFetchTaggedDriverData('idft', gxPrintingDriverBaseID, &draftTable);
  2077.             require(anErr == noErr, FailedToLoadDraftTable);
  2078.             
  2079.             // Save the draft table handle in our globals
  2080.             (*hGlobals)->draftTable = draftTable;
  2081.         }
  2082.         else    //    T => We need to setup better low resolution halftones
  2083.         {
  2084.             short    plane;
  2085.             
  2086.             // Use halftones that will look better at 72 dpi resolution than our default values.
  2087.             
  2088.             // Use the same angle and frequency for all planes, because orderDitherDot
  2089.             // won't moire on us
  2090.             for (plane = 0; plane < 4; ++plane)
  2091.             {
  2092.                 pImageData->theSetup.planeSetup[plane].planeHalftone.angle = ff(0);
  2093.                 pImageData->theSetup.planeSetup[plane].planeHalftone.frequency = ff(9);
  2094.                 pImageData->theSetup.planeSetup[plane].planeHalftone.method = gxDispersedDot;
  2095.             }
  2096.         }
  2097.         
  2098.         // Determine the StartSendPage command string to use depending upon whether the user choose birdirectional or
  2099.         // unidirectional motion.
  2100.         
  2101.         if (isJobNotFinalQuality)
  2102.         {
  2103.             // Tell the Printing Manager which "start send page" string to send to the device (the bidirectional
  2104.             // or unidirectional string)
  2105.             
  2106.             if ( theMotion.direction == doUnidirectional )
  2107.                 pImageData->packageControls.startPageStringID = kLowResUniDirID;
  2108.             else
  2109.                 pImageData->packageControls.startPageStringID = kLowResBiDirID;
  2110.         }
  2111.         
  2112.         // Update the packaging data to reflect the lower resolution
  2113.         pImageData->packagingInfo.headHeight         = 8;        // 8 pins (instead of 24)
  2114.         pImageData->packagingInfo.numberPasses     = 1;        // in 1 head pass
  2115.         pImageData->packagingInfo.passOffset         = 0;        // with no space between passes
  2116.     }
  2117.     else    //    T => Final quality job
  2118.     {
  2119.         pImageData = *hImageData;
  2120.                 
  2121.         // Tell the Printing Manager which "start send page" string to send to the device (the bidirectional
  2122.         // or unidirectional string)
  2123.         
  2124.         if ( theMotion.direction == doUnidirectional )
  2125.             pImageData->packageControls.startPageStringID = kHighResUniDirID;
  2126.         else
  2127.             pImageData->packageControls.startPageStringID = kHighResBiDirID;
  2128.  
  2129.         // image at 216 dpi
  2130.         pImageData->hImageRes = ff(216);
  2131.         pImageData->vImageRes = ff(216);
  2132.     }
  2133.     
  2134.     // If the printer doesn't have a color ribbon, set up for black and white printing
  2135.     if ( !PrinterHasColorRibbon() )
  2136.     {
  2137.         pImageData = *hImageData;
  2138.  
  2139.         // one plane, no color flags, move the halftone info up into correct position
  2140.         pImageData->theSetup.planes = 1;
  2141.         pImageData->packagingInfo.colorPasses = 1;
  2142.         pImageData->packagingInfo.packageOptions = 0;
  2143.         pImageData->theSetup.planeSetup[0] = pImageData->theSetup.planeSetup[3];
  2144.         pImageData->theSetup.planeSetup[0].planeHalftone.tinting = gxLuminanceTint;
  2145.         pImageData->theSetup.planeSetup[0].planeHalftone.tintSpace = gxRGBSpace;
  2146.     }
  2147.  
  2148.  
  2149. /******* Clean-up *******/
  2150.  
  2151. FailedToLoadDraftTable:
  2152. Forward_GXSetupImageData:
  2153.     return(anErr);
  2154. }
  2155. /* SD_SetupImageData */
  2156.  
  2157.  
  2158. /****************************************************************************************
  2159.  
  2160.                             SD_FetchTaggedData
  2161.                             
  2162.     function:
  2163.                 This routine is called by the Printing Manager when a resource is fetched
  2164.                 from some resource file.  This driver overrides this message to determine
  2165.                 when someone is fetching the 'cust' resource.  If this resource
  2166.                 is being fetched, and the job we're processing is not best quality, then
  2167.                 we lower the resolution in the 'cust' resource handle returned to be 72 dpi.
  2168.                 This ensures the translation from QuickDraw to QuickDraw GX is done at the
  2169.                 proper resolution.
  2170.                 
  2171.     parameters:    
  2172.                 rsrcType            type of the resource being retrieved
  2173.                 rsrcID            resource ID of the resource being retrieved
  2174.                 theRsrc            handle to the resource retrieved
  2175.                 owner                indicates who is issuing the request; only look at owners == 'drvr'
  2176.                 
  2177.     returns:
  2178.                 OSErr
  2179.  
  2180. ****************************************************************************************/
  2181. OSErr SD_FetchTaggedData(ResType rsrcType, short rsrcID, Handle *theRsrc, OSType owner)
  2182. {
  2183.     OSErr        anErr;
  2184.     
  2185.     if (owner == 'drvr')                                                    //    T => Fetching a driver resource
  2186.     {
  2187.         if (    (rsrcType == gxTrayCountDataType)    &&                    //    T => type is trayCountData
  2188.                 (rsrcID == gxTrayCountDataID)                            //    T => ID is trayCountData
  2189.             )
  2190.         {
  2191.             // Remap as required
  2192.             rsrcID = ((PrinterHasTrays() > 0) ? kDefaultSheetFeederRsrcID : kDefaultTrayRsrcID);
  2193.         }
  2194.         else if (    (rsrcType == gxTrayNameDataType)    &&            //    T => type is trayName
  2195.                         (rsrcID == kDefaultSheetFdrTray1NameID)    //    T => ID is trayData
  2196.             )
  2197.         {
  2198.             // Remap as required
  2199.             rsrcID = ((PrinterHasTrays() > 0) ? kDefaultSheetFdrTray1NameID : kDefaultTrayNameID);
  2200.         }
  2201.     }
  2202.     
  2203.     // First fetch the actual resource
  2204.     anErr = Forward_GXFetchTaggedData(rsrcType, rsrcID, theRsrc, owner);
  2205.     require(anErr == noErr, FetchTaggedData);
  2206.     
  2207.     if (    (owner == 'drvr')                &&        //    T => Fetching a driver resource
  2208.             (rsrcType == gxCustType)    &&        //    T => type is 'cust'
  2209.             (rsrcID == gxCustID)            &&        //    T => ID is -8192
  2210.             !JobIsBestQuality()                    //    T => Doing rough output
  2211.         )
  2212.     {
  2213.         gxCustomizationHdl    custData;
  2214.         
  2215.         // Change the 'cust' resolution to specify low res translation from QuickDraw to QuickDraw GX
  2216.         (*custData)->horizontalResolution = 72;
  2217.         (*custData)->verticalResolution = 72;
  2218.     }
  2219.  
  2220.  
  2221. /******* Clean-up *******/
  2222.  
  2223. FetchTaggedData:
  2224.     return(anErr);
  2225. }
  2226. /* SD_FetchTaggedData */
  2227.  
  2228.  
  2229. /****************************************************************************************
  2230.  
  2231.                             SD_DefaultDesktopPrinter
  2232.                             
  2233.     function:
  2234.                 This routine is called by the Printing Manager when a new desktop printer is
  2235.                 created.  We take this opportunity to open a connection to the LQ printer to
  2236.                 see how it's configured.  Specifically, we determine if there are trays
  2237.                 attached and if there is a color ribbon installed.  Based upon the device query,
  2238.                 we update the desktop printer file.
  2239.                 
  2240.     parameters:    
  2241.                 printerName        Name of the printer being created
  2242.                 
  2243.     returns:
  2244.                 OSErr
  2245.  
  2246. ****************************************************************************************/
  2247. OSErr SD_DefaultDesktopPrinter(Str31 printerName)
  2248. {
  2249.     OSErr        anErr;
  2250.     
  2251.     // First let the Printing Manager create the desktop printer
  2252.     anErr = Forward_GXDefaultDesktopPrinter(printerName);
  2253.     require(anErr == noErr, DefaultDesktopPrinter);
  2254.     
  2255.     // Optional step (now removed): during creation of the printer we could open a connection
  2256.     // to get the current configuration.  However, this has the disadvantage of making the user
  2257.     // wait until the printer is available.  The user can force a configuration update by printing
  2258.     // any document to the printer (even a blank one)
  2259.     
  2260.     // Now we attempt to open a connection to the device (it will update the config. file)
  2261. //    anErr = Send_GXOpenConnection();
  2262. //    require(anErr == noErr, OpenConnection);
  2263.     
  2264.     // A side effect of opening the connection will be that we will have already updated
  2265.     // the configuration information (in the file) that specifies whether a color ribbon
  2266.     // is installed and the number of sheet feeder trays attached (if any). ## The only additional
  2267.     // thing we'd want to do here is to update the number of trays specified in the desktop
  2268.     // printer file to be the actual number of trays attached to the device.  Currently, the 
  2269.     // system assumes the number of trays attached is equivalent to the number of default
  2270.     // trays specified in our driver resources.  Though we can query the printer for the 
  2271.     // exact number of trays, we cannot update the info. in the config. file that specifies
  2272.     // the exact number of trays.  We need a RemoveTrayInfo routine.
  2273.     
  2274.     // Now we just close down the connection
  2275. //    anErr = Send_GXCloseConnection();
  2276. //    check(anErr == noErr);
  2277.  
  2278.     
  2279. /******* Clean-up *******/
  2280.  
  2281. OpenConnection:
  2282. DefaultDesktopPrinter:
  2283.     return(anErr);
  2284. }
  2285. /* SD_DefaultDesktopPrinter */
  2286.  
  2287.  
  2288. /****************************************************************************************
  2289.  
  2290.                             SD_GetDTPMenuList
  2291.                             
  2292.     function:
  2293.                 NOOP.
  2294.                 
  2295.     parameters:    
  2296.                 hMenu            Handle to the menu that's being built
  2297.                 
  2298.     returns:
  2299.                 OSErr
  2300.  
  2301. ****************************************************************************************/
  2302. OSErr SD_GetDTPMenuList(MenuHandle hMenu)
  2303. {
  2304.     return(Forward_GXGetDTPMenuList(hMenu));
  2305. }
  2306. /* SD_GetDTPMenuList */
  2307.  
  2308.  
  2309. /****************************************************************************************
  2310.  
  2311.                             SD_DTPMenuSelect
  2312.                             
  2313.     function:
  2314.                 This routine is called by the Printing Manager when a menu item in the Finder's
  2315.                 Printer menu is selected.  This routine determines if the menu item selected
  2316.                 is the "Input Tray…" item. If it's, then display the dialog which lets the user
  2317.                 specify the paper in the LQ's sheet feeder if we know there are some trays
  2318.                 attached to the printer.  Otherwise, we just pass the item on to others in the chain.
  2319.                 
  2320.     parameters:    
  2321.                 itemNum        Menu item number that was selected
  2322.                 
  2323.     returns:
  2324.                 OSErr
  2325.  
  2326. ****************************************************************************************/
  2327. OSErr SD_DTPMenuSelect(short itemNum)
  2328. {
  2329.     OSErr        anErr;
  2330.     
  2331.     if ((itemNum == gxInputTraysMenuItem) && (PrinterHasTrays() > 0))    //    T => User wants to configure the input trays
  2332.     {
  2333.         anErr = DoSheetfeederDialog();
  2334.         
  2335.     }
  2336.     else    //    T => We didn't process the item
  2337.     {
  2338.         // Pass the message on to others in the chain
  2339.         anErr = Forward_GXDTPMenuSelect(itemNum);
  2340.     }
  2341.     
  2342.     check(anErr == noErr);
  2343.  
  2344.     return(anErr);
  2345. }
  2346. /* SD_DTPMenuSelect */
  2347.  
  2348.  
  2349. /****************************************************************************************
  2350.  
  2351.                             SD_RasterPackageBitmap
  2352.                             
  2353.     function:
  2354.                 This routine is called by the Printing Manager when it has completed rendering
  2355.                 a single portion of a raster page and the driver should now package the data
  2356.                 and output it to the device.  This routine is called to package one complete band.
  2357.                 
  2358.                 It routine does the following:
  2359.                     
  2360.                 1)    Starts filling the buffer from buffer + bufferPos.  Remember
  2361.                     that this pointer may not be word aligned - so be careful
  2362.                     assigning things into it.
  2363.                     
  2364.                 2)    Puts a "fake" set of set margins commands at
  2365.                     the begining of the data.  Since most of the time we don't
  2366.                     know the margins, we save away the value of the bufferPos,
  2367.                     and backpatch it after we have finished with the bitmap.
  2368.                     
  2369.                 3)    Adds in the rotated data for your printer.  The data to stuff starts
  2370.                     at location pPackage->startRaster * pPackage->bitmapToPackage->rowBytes (startY)
  2371.                     in the pPackage->bitmapToPackage bitmap.  Stuffs the bits from here until
  2372.                     we reach startY + <the band size>, which is the size of our single
  2373.                     band in this resolution mode.  Increment our number by 
  2374.                     <your pass offset> + 1, which is the number of microspaces
  2375.                     we will send between head passes to form this band.   Take care
  2376.                     that we don't step off of the end of the bitmap in this operation,
  2377.                     since we may be called with startY at the end of the offscreen if the first part
  2378.                     of the band is white.
  2379.                     
  2380.                     colorBand contains the color band which we should be stuffing, from
  2381.                     1 to the number of color passes our printer needs (4).
  2382.                     Packs in the correct color band.  The packager will call us once
  2383.                     for each color band, and correctly handle line feeds and backward
  2384.                     line feeds to do the correct thing.  If your printer takes full
  2385.                     RGB or CYMK data, define your number of colors to be
  2386.                     1 and pack the full RGB or CYMK data with the one call.
  2387.                     
  2388.                     If you request kSendAllColors in your raster pack resource, then this
  2389.                     message will always be called for all color passes, even those that
  2390.                     do not have data on them.  For some printers, this is useful.  For the
  2391.                     case of the ImageWriter, this option is not specified, so this message
  2392.                     will only be sent for colors that actually have dirty bits within them.
  2393.                     
  2394.                 4)    Backpatches SetMargins from the saved value in step 2) now that we
  2395.                     know the margins.
  2396.                     
  2397.                 5)    Increments bufferPos by the number of bytes we have
  2398.                     added to the buffer.  Be sure to take into account the Set Margins
  2399.                     command.
  2400.  
  2401.     parameters:        
  2402.                 whatToPackage        info. about the bitmap whose data is to be sent to the printer
  2403.                 buffer                buffer in which to place the packaged data
  2404.                 bufferPos            position within buffer of where to place the packaged data
  2405.                 imageData            handle to the raster image data info.
  2406.                 
  2407.     returns:
  2408.                 OSErr
  2409.  
  2410. ****************************************************************************************/
  2411. OSErr SD_RasterPackageBitmap(    gxRasterPackageBitmapRec    *whatToPackage, 
  2412.                                         Ptr                                 buffer,
  2413.                                         unsigned long                     *bufferPos, 
  2414.                                         gxRasterImageDataHdl            imageData)
  2415. {
  2416.     OSErr                    anErr = noErr;
  2417.     ScanLinePtr            pTheScanLine;            // Pointer to the start of scan line data
  2418.     unsigned short        firstDirty;                // First dirty pixel
  2419.     Boolean                bandIsDirty;            // Is this band dirty?
  2420.     unsigned short        whichCol;                // Index into the scan line data of where to place the next data bytes
  2421.     unsigned short        x;                            
  2422.     unsigned long        tempColumn;                // Placeholder for the column of data we're currently assembling
  2423.                                                         //    for 72 dpi:     only high order byte is used
  2424.                                                         //    for 216 dpi:    highest order three bytes are used
  2425.     Ptr                    basePtr;                    // Pointer to current X byte
  2426.     unsigned char        outputMask;                // Mask of bit to set in rotated image
  2427.     unsigned char        inputMask;                // Mask of bit to look at in X
  2428.     unsigned short        yPointerOffset;        // Increment pointer by this to get to next scanline
  2429.     unsigned short        endY;                        //    Last scan line to examine (top-to-bottom)
  2430.     unsigned short        endX;                        //    Last pixel column to examine (left-to-right)
  2431.     unsigned short        incrY;                    //    Number of scan lines to increment by when advancing to the next scan line
  2432.     short                    bytesPerBand;            //    Number of bytes in a single band (1 for 72 dpi, 3 for 216 dpi)
  2433.             
  2434.  
  2435.     // Determine the number of bytes that are in a single band 
  2436.     if ( (*imageData)->hImageRes == ff(72) )    //    T => Low resolution output
  2437.         bytesPerBand = 1;
  2438.     else
  2439.         bytesPerBand = 3;
  2440.     
  2441.     //    Overlay a scan line structure on the buffer we're filling in 
  2442.     pTheScanLine = (ScanLinePtr) (buffer + *bufferPos);
  2443.     
  2444.     // Set color mode for this scan line, if needed 
  2445.     
  2446.     pTheScanLine->cColorEscape = kEscape;
  2447.     pTheScanLine->cSetColorCommand = kSetColorCommand;
  2448.     
  2449.     if ( (*imageData)->packagingInfo.colorPasses == 4 )    //    T => Doing four pass color output
  2450.     {
  2451.         switch (whatToPackage->colorBand)    //    Determine which color to select
  2452.         {
  2453.             case 1: // yellow
  2454.                 pTheScanLine->cColor    = '1';
  2455.                 break;
  2456.                 
  2457.             case 2: // magenta
  2458.                 pTheScanLine->cColor    = '2';
  2459.                 break;
  2460.  
  2461.             case 3: // cyan
  2462.                 pTheScanLine->cColor    = '3';
  2463.                 break;
  2464.                 
  2465.             case 4: // black
  2466.                 pTheScanLine->cColor    = '0';
  2467.                 break;
  2468.         }
  2469.     }
  2470.     else    //    T => Just doing black and white printing; select the color black
  2471.         pTheScanLine->cColor = '0';
  2472.  
  2473.     // We start out with no dirty bits
  2474.     firstDirty = 0;
  2475.     bandIsDirty = false;
  2476.     
  2477.     // Set our array index to zero
  2478.     whichCol = 0;
  2479.     
  2480.     // Get the byte pointer for the start of this color band
  2481.     basePtr = whatToPackage->bitmapToPackage->image;
  2482.     
  2483.     // Get the byte pointer for the start of the first scan line
  2484.     basePtr += whatToPackage->startRaster * whatToPackage->bitmapToPackage->rowBytes;
  2485.             
  2486.     // Save away loop invariants
  2487.     
  2488.     endY = whatToPackage->startRaster + (*imageData)->packagingInfo.headHeight;    // Ending Y scan line
  2489.     incrY = (*imageData)->packagingInfo.passOffset + 1;                                    // Number of scanlines to increment by
  2490.     endX = whatToPackage->dirtyRect.right;                                                        // Ending X pos
  2491.     yPointerOffset = incrY * whatToPackage->bitmapToPackage->rowBytes;                // amount to add to the input pointer to move to the next scanline
  2492.  
  2493.     // If the ending position is too large for the bitmap we have been given,
  2494.     //truncate it, so that we don't print garbage
  2495.  
  2496.     if (endY > whatToPackage->bitmapToPackage->height)
  2497.          endY = whatToPackage->bitmapToPackage->height;
  2498.     
  2499.     // Start with the first bit in the byte sub-band
  2500.     inputMask = 0x80;
  2501.  
  2502.     // For the entire width of the scan line, move a rolling mask along in the
  2503.     // X direction, rotating up 8 or 24 bits of Y data per column.
  2504.     
  2505.     for (x = 0; x < endX; x++)
  2506.     {        
  2507.         Ptr    thePtr;
  2508.  
  2509.         // The bits in this column are clear to begin with
  2510.         tempColumn = 0;
  2511.         
  2512.         // Which byte(s) to look at in the input buffer
  2513.         thePtr = basePtr;
  2514.         
  2515.         // For the number of bytes in a single band, scan through each single  
  2516.         // byte sub-band, setting each of the 8 bits = the bit in that scan line
  2517.         {
  2518.             short                    bitsPerByte;
  2519.             short                    byteSubBand = bytesPerBand;
  2520.             unsigned char        *currByte = (unsigned char *) &tempColumn;
  2521.             short                    currYPos;
  2522.             
  2523.             currYPos = whatToPackage->startRaster;
  2524.             
  2525.             do
  2526.             {
  2527.                 // Where to place the bit in the output. The LQ takes the bit pattern upside down.
  2528.                 outputMask = 0x01;
  2529.         
  2530.                 bitsPerByte = 8;
  2531.                 while ( (bitsPerByte > 0) && (currYPos < endY) )
  2532.                 {
  2533.                     // If we have a bit turned on in the input, rotate it into the output
  2534.                     if ( ((*thePtr) & inputMask) != 0 )
  2535.                         *currByte |= outputMask;
  2536.         
  2537.                     // move onto next position in the output data                
  2538.                     outputMask <<= 1;
  2539.                     
  2540.                     // move onto the next scan line in the input data
  2541.                     thePtr += yPointerOffset;
  2542.                     
  2543.                     // Indicate we processed one of the bits
  2544.                     bitsPerByte--;
  2545.                     
  2546.                     // Keep track of our Y position as we move down the column
  2547.                     currYPos += incrY;
  2548.                 }
  2549.                 
  2550.                 if (currYPos >= endY)    //    T => We're done with this column
  2551.                     break;
  2552.                     
  2553.                 // Indicate we processed one of the byte rows in the band
  2554.                 byteSubBand--;
  2555.                 
  2556.                 // Bump to the next byte to fill in tempColumn
  2557.                 currByte++;
  2558.             }
  2559.             while (byteSubBand > 0);
  2560.         }
  2561.             
  2562.         // Save the column info (a max. of three bytes). Note: we'll only advance whichCol based upon the number of bytes per band
  2563.         BlockMove((Ptr) &tempColumn, (Ptr) &(pTheScanLine->iTheData[whichCol]), 3);
  2564.         
  2565.         // If we have some form of data, then mark that this band is dirty
  2566.         if (tempColumn != 0)
  2567.         {
  2568.             if (!bandIsDirty)    //    T => Not already dirty; remember the first dirty pixel
  2569.             {
  2570.                 /* These are the first dirty pixels we have seen so far */
  2571.                 bandIsDirty = true;
  2572.                 firstDirty = x;
  2573.             }
  2574.         }
  2575.             
  2576.         // If we have some dirty bits, adjust the whichCol variable based upon the number of bytes in a band
  2577.         if (bandIsDirty)
  2578.         {
  2579.             // Move on to the next column or set of columns
  2580.             whichCol += bytesPerBand;
  2581.         }
  2582.  
  2583.         // Position for the next bit in the input byte currently referenced by basePtr
  2584.         inputMask >>= 1;
  2585.         
  2586.         if (inputMask == 0)    //    T => Need to reset the input mask and advance the pointer
  2587.         {
  2588.             // Get the next byte
  2589.             basePtr++;
  2590.             
  2591.             // Reset the bit mask to the first bit
  2592.             inputMask = 0x80;
  2593.         }
  2594.     } // end of loop for width of bitmap
  2595.  
  2596.     // If we have a dirty band, fill in the left margin setting and add a carriage return to the end
  2597.     if (bandIsDirty)
  2598.     {            
  2599.         // Set the left margin to be the first dirty pixel in the scan line
  2600.         {
  2601.             SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  2602.             
  2603.             check(hGlobals);
  2604.             
  2605.             // Stuff in the set margin command
  2606.             
  2607.             pTheScanLine->cMarginsEscape = kEscape;
  2608.             pTheScanLine->cMarginsCommand = (bytesPerBand == 1) ? kLowResMarginsCommand : kHighResMarginsCommand;
  2609.             
  2610.             // Convert left margin into ASCII and place it at the start of the scan line
  2611.             Long2Dec((*hGlobals)->leftMargin + firstDirty, (Ptr) (pTheScanLine->cIndentDistance));
  2612.         }
  2613.         
  2614.         // Now fill in the last escape sequence command depending upon if we're doing low-res or high-res graphics
  2615.         
  2616.         pTheScanLine->cEscape = kEscape;
  2617.         pTheScanLine->cCommand = (bytesPerBand == 1)    ? kLowResGraphicsCommand : kHighResGraphicsCommand;
  2618.  
  2619.         // If we're doing high-res, then whichCol must be divided by three to compensate for the 3-byte buffer entries
  2620.         {
  2621.             short        adjustedWhichCol = whichCol;
  2622.             
  2623.             if (bytesPerBand == 3)
  2624.                 adjustedWhichCol /= 3;
  2625.                 
  2626.             Long2Dec(adjustedWhichCol, (Ptr) (pTheScanLine->cLineStrLength));
  2627.         }
  2628.         
  2629.         
  2630.         //    Increment the count of the number of bytes that have been added to the buffer
  2631.         *bufferPos += kScanLineHdrSize + whichCol;
  2632.  
  2633.         // Lastly, put a <cr> at the end of the line
  2634.         *(buffer + *bufferPos) = '\n';
  2635.         *bufferPos += 1;
  2636.     }
  2637.         
  2638.     return(anErr);
  2639. }
  2640. /* SD_RasterPackageBitmap */
  2641.  
  2642.  
  2643. /****************************************************************************************
  2644.  
  2645.                             SD_RasterLineFeed
  2646.                             
  2647.     function:
  2648.                 This routine is called by the Printing Manager to send the appropriate line
  2649.                 feed commands to the printer i norder to skip up or down the page the 
  2650.                 equivalent of lineFeedSize pixels.
  2651.                 
  2652.     parameters:    
  2653.                 lineFeedSize    number of pixels to line feed by
  2654.                 buffer            buffer in which to place the linefeed packaging commands
  2655.                 bufferPos        offset within buffer at which to place the linefeed commands
  2656.                 imageData        handle to the raster image data
  2657.                 
  2658.     returns:
  2659.                 OSErr
  2660.  
  2661. ****************************************************************************************/
  2662. OSErr SD_RasterLineFeed(short                     *lineFeedSize, 
  2663.                                 Ptr                         buffer, 
  2664.                                 unsigned long            *bufferPos, 
  2665.                                 gxRasterImageDataHdl    imageData)
  2666. {
  2667.     OSErr        anErr = noErr;
  2668.     
  2669.     // If there is no need for any line feeds, then just return now
  2670.     if (*lineFeedSize == 0)
  2671.         return(anErr);
  2672.         
  2673.     // If we are in low res mode, we double the line feed size, as all ImageWriter LQ 
  2674.     // line feed commands are expressed at 144 dpi.
  2675.     if ( (*imageData)->vImageRes == ff(72) )
  2676.     {
  2677.         long    longLineFeedSize;
  2678.         *lineFeedSize <<= 1;
  2679.         
  2680.         // do the line feed in the default way
  2681.         longLineFeedSize = *lineFeedSize;
  2682.         anErr = Forward_GXRasterLineFeed(&longLineFeedSize, buffer, bufferPos, imageData);
  2683.         *lineFeedSize = longLineFeedSize;
  2684.         
  2685.         *lineFeedSize >>= 1;
  2686.     }
  2687.     else    //    T => In high res. mode; must determine the number of 1/144 inch and 1/216 inch line feeds needed
  2688.     {
  2689.         Ptr        nextByte;    
  2690.         Fixed        lineFeedInInches;
  2691.         Fixed        oneOver144;
  2692.         Fixed        remainder;
  2693.         short        num216FractLineFeeds;
  2694.         Fixed        num144FractLineFeeds;
  2695.         Str31        aNumber;
  2696.                         
  2697.         // Determine the location at which we'll begin inserting commands
  2698.         nextByte = buffer + *bufferPos;
  2699.         
  2700.         // Is line feed movement going to be backward?
  2701.         if ( *lineFeedSize < 0 )
  2702.         {
  2703.             *lineFeedSize = -(*lineFeedSize);    // Force positive
  2704.             
  2705.             // Add the backward direction command to the buffer
  2706.             *nextByte++ = kEscape;
  2707.             *nextByte++ = 'r';
  2708.         }
  2709.         else    //    T => Paper motion is forward
  2710.         {
  2711.             // Add the forward direction command to the buffer
  2712.             *nextByte++ = kEscape;
  2713.             *nextByte++ = 'f';
  2714.         }
  2715.         
  2716.         // Update the count of the number of bytes added to the buffer
  2717.         *bufferPos += 2;
  2718.         
  2719.         // Determine the number of inches we need to skip with the line feed command
  2720.         lineFeedInInches = FixDiv( IntToFixed(*lineFeedSize), ff(216) );
  2721.         
  2722.         // Determine the integral number of 1/144 inch increments the line feed space comprises
  2723.         
  2724.         oneOver144 = FixDiv(ff(1), ff(144));
  2725.         num144FractLineFeeds = FixDiv( lineFeedInInches, oneOver144 );
  2726.         
  2727.         // Determine the remaining 1/216 inch line feeds we'll need to add to the buffer
  2728.         
  2729.         remainder = lineFeedInInches - FixMul( IntToFixed( FixedToInt(num144FractLineFeeds) ), oneOver144 );
  2730.         num216FractLineFeeds = FixedToInt( FixDiv( remainder, FixDiv( ff(1), ff(216) ) ) );
  2731.         
  2732.         // Send the line feed spacing commands and the line feeds necessary for the 1/144th's portion of the movement
  2733.         {
  2734.             short        numOne144ths = FixedToInt(num144FractLineFeeds);
  2735.             
  2736.             if (numOne144ths >= 99)    //    T => We can do a max. of 99/144 inch movement at a time
  2737.             {
  2738.                 //    Add the line feed spacing command to the buffer
  2739.                 *nextByte++ = kEscape;
  2740.                 *nextByte++ = 'T';
  2741.                 *nextByte++ = '9';
  2742.                 *nextByte++ = '9';
  2743.                 
  2744.                 // Update the count of the number of bytes added to the buffer
  2745.                 *bufferPos += 4;
  2746.         
  2747.                 do
  2748.                 {
  2749.                     *nextByte++ = kLineFeed;        // line feed
  2750.                     
  2751.                     // Update the count of the number of bytes added to the buffer
  2752.                     *bufferPos += 1;
  2753.         
  2754.                     numOne144ths -= 99;
  2755.                 }
  2756.                 while (numOne144ths >= 99);
  2757.             }
  2758.                 
  2759.             // Send remaining line feeds to finish off the 1/144th's portion of the movement
  2760.  
  2761.             if (numOne144ths > 0)    //    T => Still more movement
  2762.             {
  2763.                 *nextByte++ = kEscape;
  2764.                 *nextByte++ = 'T';
  2765.                 
  2766.                 NumToString(numOne144ths, (unsigned char *) aNumber);
  2767.                 if ( StrLength(aNumber) == 1 )
  2768.                 {
  2769.                     *nextByte++ = '0';
  2770.                     *nextByte++ = aNumber[1];
  2771.                 }
  2772.                 else
  2773.                 {
  2774.                     *nextByte++ = aNumber[1];
  2775.                     *nextByte++ = aNumber[2];
  2776.                 }
  2777.                 
  2778.                 // Add the linefeed character
  2779.                 *nextByte++ = kLineFeed;
  2780.  
  2781.                 // Update the count of the number of bytes added to the buffer
  2782.                 *bufferPos += 5;
  2783.             }
  2784.         }
  2785.         
  2786.         // Now send any spacing command for the remaining 1/216th portion of the movement if needed
  2787.         if (num216FractLineFeeds > 0)
  2788.         {
  2789.             NumToString(num216FractLineFeeds, (unsigned char *) aNumber);
  2790.             
  2791.             // Add the command to the buffer: <Esc> t <num line feeds>
  2792.             
  2793.             *nextByte++ = kEscape;
  2794.             *nextByte++ = 't';
  2795.             *nextByte = aNumber[1];
  2796.             
  2797.             // Bump the buffer byte count to account for these new characters
  2798.             *bufferPos += 3;
  2799.         }
  2800.  
  2801.         // We always handle the entire linefeed request so we can zero lineFeedSize
  2802.         *lineFeedSize = 0;
  2803.     }
  2804.  
  2805.     return(anErr);
  2806. }
  2807. /* SD_RasterLineFeed */
  2808.  
  2809.  
  2810.